利用Golang反代某AI的API

发布于 27 天前  84 次阅读


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

反代用的Golang源码

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源码

编写Dockerfile

# 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并反代

version: '3.3'
services:
    openai:
        container_name: openai
        restart: always
        image: limour/openai
    
networks:
  default:
    external: true
    name: ngpm

一枚爱好探索的医学生