概述
在本文中,我们将使用以下命令获取传入 HTTP 请求的客户端 IP 地址
- X-REAL-IP标头
- 如果X-REAL-IP为空,那么我们将回退到X-FORWARDED-FOR标头。
- 如果X-FORWARDED-FOR为空,那么我们将回退到http.Request 结构的RemoteAddr
请注意
- X-REAL-IP标头仅包含客户端计算机的一个 IP 地址。某些代理服务器(例如 Nginx)会根据请求之前遇到的信任代理填充此标头(如果为空)。另请注意,此标头很容易被客户端欺骗。
- X-FORWARDED-FOR 是 IP 地址列表 – 代理链接。将其视为请求跃点日志。因此,如果请求源自 IP 为ip1 的客户端,然后通过ip2的代理服务器,然后经过 IP 为ip3的负载均衡器,则X-FORWARDED-FOR的值将为“ip1,ip2, ip3”因此最好用“,”分隔。另请注意,它也很容易被客户端欺骗。仅当您控制设置标头的代理时才应使用此标头
- RemoteAddr包含客户端的真实IP地址。它是 Web 服务器从中接收连接并将响应发送到的实际物理 IP 地址。但如果客户端通过代理连接,它将给出代理的 IP 地址。另外,如果您正在使用负载平衡器或反向代理服务器,那么它会给出它们的地址。RemoteAddr代表 IP 端口组合。
在上述 3 个值中,RemoteAddr是最可靠的,但如果客户端位于代理后面或使用负载均衡器或反向代理服务器时,它永远不会给出正确的 IP 地址,因此顺序是先 X-REAL-IP ,然后X-FORWARDED-FOR ,然后是RemoteAddr。但请注意,恶意用户仍然可以创建虚假的X-REAL-IP和X-FORWARDED-FOR标头
代码
让我们看一下 GOLANG 实现的代码
package main
import (
"fmt"
"net"
"net/http"
"strings"
)
func main() {
handlerFunc := http.HandlerFunc(handleRequest)
http.Handle("/getIp", handlerFunc)
http.ListenAndServe(":8080", nil)
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
ip, err := getIP(r)
if err != nil {
w.WriteHeader(400)
w.Write([]byte("No valid ip"))
}
w.WriteHeader(200)
w.Write([]byte(ip))
}
func getIP(r *http.Request) (string, error) {
//Get IP from the X-REAL-IP header
ip := r.Header.Get("X-REAL-IP")
netIP := net.ParseIP(ip)
if netIP != nil {
return ip, nil
}
//Get IP from X-FORWARDED-FOR header
ips := r.Header.Get("X-FORWARDED-FOR")
splitIps := strings.Split(ips, ",")
for _, ip := range splitIps {
netIP := net.ParseIP(ip)
if netIP != nil {
return ip, nil
}
}
//Get IP from RemoteAddr
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return "", err
}
netIP = net.ParseIP(ip)
if netIP != nil {
return ip, nil
}
return "", fmt.Errorf("No valid ip found")
}
进行调用
curl -v -X GET http://localhost:8080/getIp
输出:
On my machine it outputs ::1 which is actually loopback address for IPV6
在您的计算机上,它将输出 127.0.0.1(IPV4)或 ::1(IPV6)