package helper import ( "net" "strings" "github.com/go-kratos/kratos/v2/transport/http" ) // GetClientIP 获取客户端真实 IP func GetClientIP(ctx http.Context) string { // 检查 X-Forwarded-For 头(多个代理时格式为 "client, proxy1, proxy2") if xff := ctx.Header().Get("X-Forwarded-For"); xff != "" { ips := strings.Split(xff, ",") for _, ip := range ips { ip = strings.TrimSpace(ip) if ip != "" { // 验证是否为合法 IP if isValidIP(ip) { return ip } } } } // 检查 X-Real-IP 头 if realIP := ctx.Header().Get("X-Real-IP"); realIP != "" { if isValidIP(realIP) { return realIP } } // 检查 X-Forwarded if forwarded := ctx.Header().Get("X-Forwarded"); forwarded != "" { // 格式可能为 "for=client-ip;host=example.com;proto=https" parts := strings.Split(forwarded, ";") for _, part := range parts { part = strings.TrimSpace(part) if strings.HasPrefix(part, "for=") { ip := strings.TrimPrefix(part, "for=") ip = strings.Trim(ip, `"`) // 可能被引号包围 if isValidIP(ip) { return ip } } } } // 直接从 RemoteAddr 获取 remoteAddr := ctx.Request().RemoteAddr if ip, _, err := net.SplitHostPort(remoteAddr); err == nil { if isValidIP(ip) { return ip } } return "" } // 验证是否为合法 IP func isValidIP(ip string) bool { parsedIP := net.ParseIP(ip) return parsedIP != nil }