package utils import ( "net/http" "net/http/httputil" "net/url" "strings" ) type httpUtil struct { } // Http 暴露接口 func Http() *httpUtil { return &httpUtil{} } // NewProxy 重写创建代理函数,加入 Host 信息 func (hu httpUtil) NewProxy(target *url.URL) *httputil.ReverseProxy { targetQuery := target.RawQuery director := func(req *http.Request) { req.Host = target.Host req.URL.Scheme = target.Scheme req.URL.Host = target.Host req.URL.Path, req.URL.RawPath = hu.joinURLPath(target, req.URL) // 过滤掉参数 if uri, err := url.Parse(req.URL.Path); err == nil { req.URL.Path = uri.Path } var rawQuery string if targetQuery == "" || req.URL.RawQuery == "" { rawQuery = targetQuery + req.URL.RawQuery } else { rawQuery = targetQuery + "&" + req.URL.RawQuery } req.URL.RawQuery = rawQuery if _, ok := req.Header["User-Agent"]; !ok { // explicitly disable User-Agent so it's not set to default value req.Header.Set("User-Agent", "") } // 补充内部调用Header req.Header.Set("X-Request-From", "internal") } return &httputil.ReverseProxy{Director: director} } func (hu httpUtil) joinURLPath(a, b *url.URL) (path, rawpath string) { if a.RawPath == "" && b.RawPath == "" { return hu.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 } func (hu httpUtil) 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 }