更新Go版本至1.24,添加对github.com/woodchen-ink/go-web-utils的依赖,优化IP获取逻辑,统一使用iputil包获取客户端IP,提升代码一致性和可读性。

This commit is contained in:
wood chen 2025-06-21 22:39:04 +08:00
parent da3200c605
commit f31c601c20
9 changed files with 59 additions and 62 deletions

9
go.mod
View File

@ -1,10 +1,15 @@
module proxy-go
go 1.23.1
go 1.24
toolchain go1.24.4
require (
github.com/andybalholm/brotli v1.1.1
golang.org/x/net v0.40.0
)
require golang.org/x/text v0.25.0 // indirect
require (
github.com/woodchen-ink/go-web-utils v1.0.0 // indirect
golang.org/x/text v0.25.0 // indirect
)

4
go.sum
View File

@ -1,5 +1,9 @@
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/woodchen-ink/go-web-utils v0.0.0-20250621140947-08c57486fe2e h1:k/D90giyDyL5hDPJGGQexqZ423WmZqRUUxc/yQ6E8ws=
github.com/woodchen-ink/go-web-utils v0.0.0-20250621140947-08c57486fe2e/go.mod h1:d+L8rZ7xekLnf679XRvfwqpl4M8RCNdWSViaB3GmpnI=
github.com/woodchen-ink/go-web-utils v1.0.0 h1:Kybe0ZPhRI4w5FJ4bZdPcepNEKTmbw3to3xLR31e+ws=
github.com/woodchen-ink/go-web-utils v1.0.0/go.mod h1:hpiT30rd5Egj2LqRwYBqbEtUXjhjh/Qary0S14KCZgw=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=

View File

@ -14,6 +14,8 @@ import (
"strings"
"sync"
"time"
"github.com/woodchen-ink/go-web-utils/iputil"
)
const (
@ -154,7 +156,7 @@ func (h *ProxyHandler) CheckAuth(token string) bool {
func (h *ProxyHandler) LogoutHandler(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
log.Printf("[Auth] ERR %s %s -> 401 (%s) no token from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 401 (%s) no token from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
@ -162,7 +164,7 @@ func (h *ProxyHandler) LogoutHandler(w http.ResponseWriter, r *http.Request) {
token := strings.TrimPrefix(auth, "Bearer ")
h.auth.tokens.Delete(token)
log.Printf("[Auth] %s %s -> 200 (%s) logout success from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] %s %s -> 200 (%s) logout success from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
@ -175,14 +177,14 @@ func (h *ProxyHandler) AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
auth := r.Header.Get("Authorization")
if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
log.Printf("[Auth] ERR %s %s -> 401 (%s) no token from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 401 (%s) no token from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
token := strings.TrimPrefix(auth, "Bearer ")
if !h.auth.validateToken(token) {
log.Printf("[Auth] ERR %s %s -> 401 (%s) invalid token from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 401 (%s) invalid token from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
@ -253,14 +255,14 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
// 验证 state
if !h.auth.validateState(state) {
log.Printf("[Auth] ERR %s %s -> 400 (%s) invalid state '%s' from %s",
r.Method, r.URL.Path, utils.GetClientIP(r), state, utils.GetRequestSource(r))
r.Method, r.URL.Path, iputil.GetClientIP(r), state, utils.GetRequestSource(r))
http.Error(w, "Invalid state", http.StatusBadRequest)
return
}
// 验证code参数
if code == "" {
log.Printf("[Auth] ERR %s %s -> 400 (%s) missing code parameter from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 400 (%s) missing code parameter from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Missing code parameter", http.StatusBadRequest)
return
}
@ -272,7 +274,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
// 验证OAuth配置
if clientID == "" || clientSecret == "" {
log.Printf("[Auth] ERR %s %s -> 500 (%s) missing OAuth credentials from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 500 (%s) missing OAuth credentials from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Server configuration error", http.StatusInternalServerError)
return
}
@ -290,7 +292,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
"client_secret": {clientSecret},
})
if err != nil {
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to get access token: %v from %s", r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to get access token: %v from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), err, utils.GetRequestSource(r))
http.Error(w, "Failed to get access token", http.StatusInternalServerError)
return
}
@ -301,21 +303,21 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
// 读取错误响应内容
bodyBytes, _ := io.ReadAll(resp.Body)
log.Printf("[Auth] ERR %s %s -> %d (%s) OAuth server returned error: %s, response: %s",
r.Method, r.URL.Path, resp.StatusCode, utils.GetClientIP(r), resp.Status, string(bodyBytes))
r.Method, r.URL.Path, resp.StatusCode, iputil.GetClientIP(r), resp.Status, string(bodyBytes))
http.Error(w, "OAuth server error: "+resp.Status, http.StatusInternalServerError)
return
}
var token OAuthToken
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to parse token response: %v from %s", r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to parse token response: %v from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), err, utils.GetRequestSource(r))
http.Error(w, "Failed to parse token response", http.StatusInternalServerError)
return
}
// 验证访问令牌
if token.AccessToken == "" {
log.Printf("[Auth] ERR %s %s -> 500 (%s) received empty access token from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 500 (%s) received empty access token from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Received invalid token", http.StatusInternalServerError)
return
}
@ -326,7 +328,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
client := &http.Client{Timeout: 10 * time.Second}
userResp, err := client.Do(req)
if err != nil {
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to get user info: %v from %s", r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to get user info: %v from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), err, utils.GetRequestSource(r))
http.Error(w, "Failed to get user info", http.StatusInternalServerError)
return
}
@ -335,7 +337,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
// 检查用户信息响应状态码
if userResp.StatusCode != http.StatusOK {
log.Printf("[Auth] ERR %s %s -> %d (%s) userinfo endpoint returned error status: %s from %s",
r.Method, r.URL.Path, userResp.StatusCode, utils.GetClientIP(r), userResp.Status, utils.GetRequestSource(r))
r.Method, r.URL.Path, userResp.StatusCode, iputil.GetClientIP(r), userResp.Status, utils.GetRequestSource(r))
http.Error(w, "Failed to get user info: "+userResp.Status, http.StatusInternalServerError)
return
}
@ -344,7 +346,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
bodyBytes, err := io.ReadAll(userResp.Body)
if err != nil {
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to read user info response body: %v from %s",
r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
r.Method, r.URL.Path, iputil.GetClientIP(r), err, utils.GetRequestSource(r))
http.Error(w, "Failed to read user info response", http.StatusInternalServerError)
return
}
@ -356,7 +358,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
var rawUserInfo map[string]interface{}
if err := json.Unmarshal(bodyBytes, &rawUserInfo); err != nil {
log.Printf("[Auth] ERR %s %s -> 500 (%s) failed to parse raw user info: %v from %s",
r.Method, r.URL.Path, utils.GetClientIP(r), err, utils.GetRequestSource(r))
r.Method, r.URL.Path, iputil.GetClientIP(r), err, utils.GetRequestSource(r))
http.Error(w, "Failed to parse user info", http.StatusInternalServerError)
return
}
@ -391,7 +393,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
// 验证用户信息
if userInfo.Username == "" {
log.Printf("[Auth] ERR %s %s -> 500 (%s) could not extract username from user info from %s",
r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
http.Error(w, "Invalid user information: missing username", http.StatusInternalServerError)
return
}
@ -400,7 +402,7 @@ func (h *ProxyHandler) OAuthCallbackHandler(w http.ResponseWriter, r *http.Reque
internalToken := h.auth.generateToken()
h.auth.addToken(internalToken, userInfo.Username, tokenExpiry)
log.Printf("[Auth] %s %s -> 200 (%s) login success for user %s from %s", r.Method, r.URL.Path, utils.GetClientIP(r), userInfo.Username, utils.GetRequestSource(r))
log.Printf("[Auth] %s %s -> 200 (%s) login success for user %s from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), userInfo.Username, utils.GetRequestSource(r))
// 返回登录成功页面
w.Header().Set("Content-Type", "text/html")

View File

@ -11,6 +11,8 @@ import (
"proxy-go/internal/utils"
"strings"
"time"
"github.com/woodchen-ink/go-web-utils/iputil"
)
type MirrorProxyHandler struct {
@ -56,7 +58,7 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
log.Printf("| %-6s | %3d | %12s | %15s | %10s | %-30s | CORS Preflight",
r.Method, http.StatusOK, time.Since(startTime),
utils.GetClientIP(r), "-", r.URL.Path)
iputil.GetClientIP(r), "-", r.URL.Path)
return
}
@ -66,7 +68,7 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Invalid URL", http.StatusBadRequest)
log.Printf("| %-6s | %3d | %12s | %15s | %10s | %-30s | Invalid URL",
r.Method, http.StatusBadRequest, time.Since(startTime),
utils.GetClientIP(r), "-", r.URL.Path)
iputil.GetClientIP(r), "-", r.URL.Path)
return
}
@ -80,7 +82,7 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Invalid URL", http.StatusBadRequest)
log.Printf("| %-6s | %3d | %12s | %15s | %10s | %-30s | Parse URL error: %v",
r.Method, http.StatusBadRequest, time.Since(startTime),
utils.GetClientIP(r), "-", actualURL, err)
iputil.GetClientIP(r), "-", actualURL, err)
return
}
@ -98,7 +100,7 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Error creating request", http.StatusInternalServerError)
log.Printf("| %-6s | %3d | %12s | %15s | %10s | %-30s | Error creating request: %v",
r.Method, http.StatusInternalServerError, time.Since(startTime),
utils.GetClientIP(r), "-", actualURL, err)
iputil.GetClientIP(r), "-", actualURL, err)
return
}
@ -131,7 +133,7 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
http.ServeFile(w, r, item.FilePath)
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(startTime), item.Size, utils.GetClientIP(r), r)
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(startTime), item.Size, iputil.GetClientIP(r), r)
return
}
}
@ -142,7 +144,7 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Error forwarding request", http.StatusBadGateway)
log.Printf("| %-6s | %3d | %12s | %15s | %10s | %-30s | Error forwarding request: %v",
r.Method, http.StatusBadGateway, time.Since(startTime),
utils.GetClientIP(r), "-", actualURL, err)
iputil.GetClientIP(r), "-", actualURL, err)
return
}
defer resp.Body.Close()
@ -183,9 +185,9 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 记录访问日志
log.Printf("| %-6s | %3d | %12s | %15s | %10s | %-30s | %s",
r.Method, resp.StatusCode, time.Since(startTime),
utils.GetClientIP(r), utils.FormatBytes(written),
iputil.GetClientIP(r), utils.FormatBytes(written),
utils.GetRequestSource(r), actualURL)
// 记录统计信息
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), written, utils.GetClientIP(r), r)
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), written, iputil.GetClientIP(r), r)
}

View File

@ -17,6 +17,7 @@ import (
"strings"
"time"
"github.com/woodchen-ink/go-web-utils/iputil"
"golang.org/x/net/http2"
)
@ -232,7 +233,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "Welcome to CZL proxy.")
log.Printf("[Proxy] %s %s -> %d (%s) from %s", r.Method, r.URL.Path, http.StatusOK, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Proxy] %s %s -> %d (%s) from %s", r.Method, r.URL.Path, http.StatusOK, iputil.GetClientIP(r), utils.GetRequestSource(r))
return
}
@ -258,7 +259,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 检查是否需要进行302跳转
if h.redirectHandler != nil && h.redirectHandler.HandleRedirect(w, r, pathConfig, decodedPath, h.client) {
// 如果进行了302跳转直接返回不继续处理
collector.RecordRequest(r.URL.Path, http.StatusFound, time.Since(start), 0, utils.GetClientIP(r), r)
collector.RecordRequest(r.URL.Path, http.StatusFound, time.Since(start), 0, iputil.GetClientIP(r), r)
return
}
@ -342,7 +343,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
// 设置最小必要的代理头部
clientIP := utils.GetClientIP(r)
clientIP := iputil.GetClientIP(r)
proxyReq.Header.Set("X-Real-IP", clientIP)
// 添加或更新 X-Forwarded-For - 减少重复获取客户端IP
@ -389,7 +390,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
http.ServeFile(w, r, item.FilePath)
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(start), item.Size, utils.GetClientIP(r), r)
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(start), item.Size, iputil.GetClientIP(r), r)
return
}
}
@ -399,10 +400,10 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
h.errorHandler(w, r, fmt.Errorf("request timeout after %v", proxyRespTimeout))
log.Printf("[Proxy] ERR %s %s -> 408 (%s) timeout from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Proxy] ERR %s %s -> 408 (%s) timeout from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
} else {
h.errorHandler(w, r, fmt.Errorf("proxy error: %v", err))
log.Printf("[Proxy] ERR %s %s -> 502 (%s) proxy error from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Proxy] ERR %s %s -> 502 (%s) proxy error from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
}
return
}
@ -450,7 +451,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
written, err = io.CopyBuffer(w, resp.Body, buf)
if err != nil && !isConnectionClosed(err) {
log.Printf("[Proxy] ERR %s %s -> write error (%s) from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Proxy] ERR %s %s -> write error (%s) from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
return
}
}
@ -461,13 +462,13 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
written, err = io.CopyBuffer(w, resp.Body, buf)
if err != nil && !isConnectionClosed(err) {
log.Printf("[Proxy] ERR %s %s -> write error (%s) from %s", r.Method, r.URL.Path, utils.GetClientIP(r), utils.GetRequestSource(r))
log.Printf("[Proxy] ERR %s %s -> write error (%s) from %s", r.Method, r.URL.Path, iputil.GetClientIP(r), utils.GetRequestSource(r))
return
}
}
// 记录统计信息
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), written, utils.GetClientIP(r), r)
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r)
}
func copyHeader(dst, src http.Header) {

View File

@ -8,6 +8,8 @@ import (
"proxy-go/internal/service"
"proxy-go/internal/utils"
"strings"
"github.com/woodchen-ink/go-web-utils/iputil"
)
// RedirectHandler 处理302跳转逻辑
@ -99,7 +101,7 @@ func (rh *RedirectHandler) performRedirect(w http.ResponseWriter, r *http.Reques
w.WriteHeader(http.StatusFound)
// 记录跳转日志
clientIP := utils.GetClientIP(r)
clientIP := iputil.GetClientIP(r)
log.Printf("[Redirect] %s %s -> 302 %s (%s) from %s",
r.Method, r.URL.Path, targetURL, clientIP, utils.GetRequestSource(r))
}

View File

@ -4,8 +4,9 @@ import (
"encoding/json"
"net/http"
"proxy-go/internal/security"
"proxy-go/internal/utils"
"time"
"github.com/woodchen-ink/go-web-utils/iputil"
)
// SecurityHandler 安全管理处理器
@ -109,7 +110,7 @@ func (sh *SecurityHandler) CheckIPStatus(w http.ResponseWriter, r *http.Request)
ip := r.URL.Query().Get("ip")
if ip == "" {
// 如果没有指定IP使用请求的IP
ip = utils.GetClientIP(r)
ip = iputil.GetClientIP(r)
}
banned, banEndTime := sh.banManager.GetBanInfo(ip)

View File

@ -4,8 +4,9 @@ import (
"fmt"
"net/http"
"proxy-go/internal/security"
"proxy-go/internal/utils"
"time"
"github.com/woodchen-ink/go-web-utils/iputil"
)
// SecurityMiddleware 安全中间件
@ -23,7 +24,7 @@ func NewSecurityMiddleware(banManager *security.IPBanManager) *SecurityMiddlewar
// IPBanMiddleware IP封禁中间件
func (sm *SecurityMiddleware) IPBanMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
clientIP := utils.GetClientIP(r)
clientIP := iputil.GetClientIP(r)
// 检查IP是否被封禁
if sm.banManager.IsIPBanned(clientIP) {

View File

@ -6,7 +6,6 @@ import (
"encoding/hex"
"fmt"
"log"
"net"
"net/http"
neturl "net/url"
"path/filepath"
@ -93,26 +92,6 @@ func GenerateRequestID() string {
return hex.EncodeToString(b)
}
func GetClientIP(r *http.Request) string {
// 优先级1: Cloudflare 提供的原始客户端 IP最准确
if ip := r.Header.Get("CF-Connecting-IP"); ip != "" {
return ip
}
// 优先级2: 通用的真实 IP 头
if ip := r.Header.Get("X-Real-IP"); ip != "" {
return ip
}
// 优先级3: 标准的转发链头部(取第一个 IP即原始客户端 IP
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
return strings.Split(ip, ",")[0]
}
// 优先级4: 直连 IP兜底方案
if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
return ip
}
return r.RemoteAddr
}
// 获取请求来源
func GetRequestSource(r *http.Request) string {
referer := r.Header.Get("Referer")