package server import ( "net/http" "net/http/httputil" "net/url" "strings" "git.magicany.cc/black1552/gf-common/log" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gctx" ) // hasProtocol 检查字符串是否包含协议前缀 func hasProtocol(s string) bool { return strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") || strings.HasPrefix(s, "ws://") || strings.HasPrefix(s, "wss://") } // BuildRequest 反向代理请求到指定主机 // 自动支持所有 HTTP 方法及 WebSocket 连接 func BuildRequest(r *ghttp.Request, host string) { // 自动添加协议前缀 targetHost := host if !hasProtocol(host) { // 根据请求判断协议:WebSocket 用 ws,普通 HTTP 用 http if r.Header.Get("Upgrade") == "websocket" { targetHost = "ws://" + host } else { targetHost = "http://" + host } } targetURL, err := url.Parse(targetHost) if err != nil { log.Error(gctx.New(), "parse target host error:", err) r.Response.WriteStatus(http.StatusInternalServerError) r.Response.Write([]byte("Invalid target host")) return } proxy := httputil.NewSingleHostReverseProxy(targetURL) // 自定义 Director 来设置目标 URL,保留原始请求的所有参数 proxy.Director = func(req *http.Request) { req.URL.Scheme = targetURL.Scheme req.URL.Host = targetURL.Host req.URL.Path = r.URL.Path req.URL.RawQuery = r.URL.RawQuery // 保留原始 Host 头 req.Host = r.Host } // 错误处理 proxy.ErrorHandler = func(w http.ResponseWriter, req *http.Request, err error) { log.Error(gctx.New(), "proxy error:", err) w.WriteHeader(http.StatusBadGateway) w.Write([]byte("Bad Gateway")) } // ServeHTTP 会自动处理 WebSocket 升级和所有 HTTP 方法 proxy.ServeHTTP(r.Response.Writer, r.Request) }