voucher/internal/pkg/helper/ip.go

66 lines
1.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}