90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
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)
|
||
}
|