update reqip

This commit is contained in:
wjqserver 2025-08-01 09:05:09 +08:00
parent 99b48371b3
commit 295852e1a1

View file

@ -14,7 +14,6 @@ import (
"io" "io"
"math" "math"
"mime" "mime"
"net"
"net/http" "net/http"
"net/netip" "net/netip"
"net/url" "net/url"
@ -523,39 +522,59 @@ func (c *Context) GetReqBodyBuffer() (*bytes.Buffer, error) {
func (c *Context) RequestIP() string { func (c *Context) RequestIP() string {
if c.engine.ForwardByClientIP { if c.engine.ForwardByClientIP {
for _, headerName := range c.engine.RemoteIPHeaders { for _, headerName := range c.engine.RemoteIPHeaders {
if ipValue := c.Request.Header.Get(headerName); ipValue != "" { ipValue := c.Request.Header.Get(headerName)
// X-Forwarded-For 可能包含多个 IP约定第一个最左边是客户端 IP if ipValue == "" {
// 其他头部(如 X-Real-IP通常只有一个 continue // 头部为空, 继续检查下一个
ips := strings.Split(ipValue, ",") }
for _, singleIP := range ips {
trimmedIP := strings.TrimSpace(singleIP) // 使用索引高效遍历逗号分隔的 IP 列表, 避免 strings.Split 的内存分配
// 使用 netip.ParseAddr 进行 IP 地址的解析和格式验证 currentPos := 0
addr, err := netip.ParseAddr(trimmedIP) for currentPos < len(ipValue) {
if err == nil { nextComma := strings.IndexByte(ipValue[currentPos:], ',')
// 成功解析到合法的 IP 地址格式,立即返回
return addr.String() var ipSegment string
} if nextComma == -1 {
// 如果当前 singleIP 无效,继续检查列表中的下一个 // 这是列表中的最后一个 IP
ipSegment = ipValue[currentPos:]
currentPos = len(ipValue) // 结束循环
} else {
// 截取当前 IP 段
ipSegment = ipValue[currentPos : currentPos+nextComma]
currentPos += nextComma + 1 // 移动到下一个 IP 段的起始位置
}
// 去除空格并检查是否为空 (例如 "ip1,,ip2")
trimmedIP := strings.TrimSpace(ipSegment)
if trimmedIP == "" {
continue
}
// 使用 netip.ParseAddr 进行 IP 地址的解析和验证
addr, err := netip.ParseAddr(trimmedIP)
if err == nil {
// 成功解析到合法的 IP, 立即返回
return addr.String()
} }
} }
} }
} }
// 如果没有启用 ForwardByClientIP 或头部中没有找到有效 IP回退到 Request.RemoteAddr // 回退到 Request.RemoteAddr 的处理
// RemoteAddr 通常是 "host:port" 格式,但也可能直接就是 IP 地址 // 优先使用 netip.ParseAddrPort, 它比 net.SplitHostPort 更高效且分配更少
remoteAddrStr := c.Request.RemoteAddr addrp, err := netip.ParseAddrPort(c.Request.RemoteAddr)
ip, _, err := net.SplitHostPort(remoteAddrStr) // 尝试分离 host 和 port if err == nil {
if err != nil { // 成功从 "ip:port" 格式中解析出 IP
// 如果分离失败,意味着 remoteAddrStr 可能直接就是 IP 地址(或畸形) return addrp.String()
ip = remoteAddrStr // 此时将整个 remoteAddrStr 作为候选 IP
} }
// 对从 RemoteAddr 中提取/使用的 IP 进行最终的合法性验证 // 如果上面的解析失败 (例如 RemoteAddr 只有 IP, 没有端口),
addr, parseErr := netip.ParseAddr(ip) // 则尝试将整个字符串作为 IP 地址进行解析
if parseErr == nil { addr, err := netip.ParseAddr(c.Request.RemoteAddr)
return addr.String() // 成功解析并返回合法 IP if err == nil {
return addr.String()
} }
// 所有方法都失败, 返回空字符串
return "" return ""
} }