gf-common/server/gateway.go

74 lines
2.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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"))
}
proxy.ModifyResponse = func(resp *http.Response) error {
// 获取原始响应的 Header
for k, v := range resp.Header {
r.Response.Header().Set(k, v[0])
}
return nil
}
// ServeHTTP 会自动处理 WebSocket 升级和所有 HTTP 方法
// 使用 RawWriter() 获取原始的 http.ResponseWriter避免 gf 框架的封装影响
proxy.ServeHTTP(r.Response.RawWriter(), r.Request)
r.Response.WriteJson(r.Response.RawWriter())
}