package server import ( "fmt" "io" "net/http" "net/http/httputil" "net/url" "strings" "git.magicany.cc/black1552/gf-common/log" "github.com/gogf/gf/v2/net/gclient" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/text/gstr" ) // 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) { if gstr.Contains(r.RequestURI, "/ws") { proxyWebSocket(r, host) return } client := gclient.New() // 构建目标URL而不是直接复制RequestURI targetURL := host + r.URL.Path if r.URL.RawQuery != "" { targetURL += "?" + r.URL.RawQuery } // 复制请求头 for key, values := range r.Header { for _, value := range values { client.SetHeader(key, value) } } response, err := client.DoRequest(gctx.New(), r.Method, targetURL, r.GetBody()) if err != nil { log.Error(gctx.New(), "request error:", err) panic(fmt.Sprintf("request error: %v", err)) } defer response.Body.Close() // 读取响应体 respBody, err := io.ReadAll(response.Body) if err != nil { log.Error(gctx.New(), "read response body error:", err) panic(fmt.Sprintf("read response body error: %v", err)) } // 复制响应头 for key, values := range response.Header { for _, value := range values { r.Response.Header().Add(key, value) } } // 设置响应状态码并写入响应体 r.Response.Status = response.StatusCode r.Response.Write(respBody) } // proxyWebSocket 处理 WebSocket 连接的代理 func proxyWebSocket(r *ghttp.Request, targetHost string) { // 解析目标主机 URL 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) // 修改请求 URL,保留原始路径和查询参数 r.URL.Scheme = targetURL.Scheme r.URL.Host = targetURL.Host log.Info(gctx.New(), r.GetBodyString()) // 处理 WebSocket 连接 proxy.ServeHTTP(r.Response.Writer, r.Request) }