利用Golang反代某AI的API

某AI的API在部分地区不太稳定,这里可以在稳定的地区进行反代。

反代用的Golang源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package main

import (
"log"
"net/http"
"net/http/httputil"
"net/url"
"strings"
)

type RProxy struct {
remote *url.URL
}

func GoReverseProxy(this *RProxy) *httputil.ReverseProxy {
remote := this.remote

proxy := httputil.NewSingleHostReverseProxy(remote)

proxy.Director = func(request *http.Request) {
targetQuery := remote.RawQuery
request.URL.Scheme = remote.Scheme
request.URL.Host = remote.Host
request.Host = remote.Host // todo 这个是关键
request.URL.Path, request.URL.RawPath = joinURLPath(remote, request.URL)

if targetQuery == "" request.URL.RawQuery == "" {
request.URL.RawQuery = targetQuery + request.URL.RawQuery
} else {
request.URL.RawQuery = targetQuery + "&" + request.URL.RawQuery
}
if _, ok := request.Header["User-Agent"]; !ok {
// explicitly disable User-Agent so it's not set to default value
request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36")
}
log.Println("request.URL.Path:", request.URL.Path, "request.URL.RawQuery:", request.URL.RawQuery)
}

// 修改响应头
proxy.ModifyResponse = func(response *http.Response) error {
response.Header.Add("Access-Control-Allow-Origin", "*")
response.Header.Add("Reverse-Proxy-Server-PowerBy", "(Hzz)https://hzz.cool")
return nil
}

return proxy
}

// go sdk 源码
func joinURLPath(a, b *url.URL) (path, rawpath string) {
if a.RawPath == "" && b.RawPath == "" {
return singleJoiningSlash(a.Path, b.Path), ""
}
// Same as singleJoiningSlash, but uses EscapedPath to determine
// whether a slash should be added
apath := a.EscapedPath()
bpath := b.EscapedPath()

aslash := strings.HasSuffix(apath, "/")
bslash := strings.HasPrefix(bpath, "/")

switch {
case aslash && bslash:
return a.Path + b.Path[1:], apath + bpath[1:]
case !aslash && !bslash:
return a.Path + "/" + b.Path, apath + "/" + bpath
}
return a.Path + b.Path, apath + bpath
}

// go sdk 源码
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}

func main() {
port := "1874"
reverseUrl := "https://api.openai.com"

remote, err := url.Parse(reverseUrl)
if err != nil {
panic(err)
}

proxy := GoReverseProxy(&RProxy{
remote: remote,
})

log.Println("当前代理地址: " + reverseUrl + " 本地监听: http://127.0.0.1:" + port)

serveErr := http.ListenAndServe(":"+port, proxy)

if serveErr != nil {
panic(serveErr)
}
}

编译Golang源码

  • 尝试用Golang静态编译可执行文件
  • CC=musl-gcc /home/jovyan/go/bin/go1.20.1 build -tags musl -o openai -trimpath -ldflags ‘-linkmode “external” -extldflags “-static” -s -w -buildid=’ ./openai.go

编写Dockerfile

1
2
3
4
5
6
7
8
# set alpine as the base image of the Dockerfile
FROM alpine:latest

# Copy over the torrc created above and set the owner to `tor`
COPY openai /bin/openai

# Set `tor` as the entrypoint for the image
ENTRYPOINT ["/bin/openai"]
  • mkdir -p ~/app/openai && cd ~/app/openai && nano Dockerfile && nano docker-compose.yml
  • 上传编译好的openai可执行文件
  • chmod +x openai
  • docker build -t limour/openai .

部署Docker并反代

1
2
3
4
5
6
7
8
9
10
11
version: '3.3'
services:
openai:
container_name: openai
restart: always
image: limour/openai

networks:
default:
external: true
name: ngpm

利用Golang反代某AI的API
https://occdn.limour.top/2607.html
Author
Limour
Posted on
March 3, 2023
Licensed under