diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26b30cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea +/tmp +*.exe +*.exe~ \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..74c2879 --- /dev/null +++ b/go.mod @@ -0,0 +1,6 @@ +module go-reverse-proxy + +go 1.15 + +require ( +) \ No newline at end of file diff --git a/handle.go b/handle.go new file mode 100644 index 0000000..c0f1500 --- /dev/null +++ b/handle.go @@ -0,0 +1,82 @@ +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 +} \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..74e0669 --- /dev/null +++ b/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "flag" + "log" + "net/http" + "net/url" +) + +func main() { + port := flag.String("p", "1874", "本地监听的端口") + reverseUrl := flag.String("r", "https://hzz.cool", "需要代理的地址") + flag.Parse() + + 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) + } +} \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..a26fea0 --- /dev/null +++ b/readme.md @@ -0,0 +1,27 @@ +# go-reverse-proxy + +> 基于go实现简单http/https的反向代理服务 + +## 使用 +- windows64 直接下载 release +- 编译 +``` +git clone +cd go-reverse-proxy + +# 编译 +go build -ldflags "-s -w" + +# 执行启动 +./go-reverse-proxy +``` + +## 参数说明 +``` +./go-reverse-proxy.exe -h + +-p string + 本地监听的端口 (default "1874") +-r string + 需要代理的地址 (default "https://hzz.cool") +``` \ No newline at end of file