概述

在本文中,我们将使用以下命令获取传入 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-IPX-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)

(adsbygoogle = window.adsbygoogle || []).push({});