66 lines
1.8 KiB
Go
66 lines
1.8 KiB
Go
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)
|
||
}
|