获取客户端IP的问题

获取请求的IP很简单,可以直接使用request.getRemoteAddr()直接获取。但由于请求在转发到接口前,会经过大量的反向代理,例如流程图中,至少要经过Nginx后,请求才会转发到接口,因此需要对请求接口的IP做处理,提取客户端真实IP地址。

nginx真实客户端ip nginx获取客户端真实ip_java

获取客户端IP的步骤

1、编写Nginx配置文件,让Nginx可以携带客户端真实IP的地址

配置Nginx的配置文件,需要反向代理服务器可以携带真实的客户端IP地址,放在请求头中。

核心参数解读:

  • $remote_addr: 如果未使用代理,配置的输出结果为客户端IP。如果使用了代理,配置的输出结果为最后一个代理服务器的IP。
  • $proxy_add_x_forwarded_for: 代表请求链。每经过一个反向代理就在请求头X-Forwarded-For后追加反向代理IP,用逗号+空格分隔。标准格式如下:X-Forwarded-For: clientIP, proxyIP1, proxyIP2(ps. 最左边的clientIp即为客户端真实IP)
server {
  listen 80;
  server_name localhost;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://192.168.11.1:10001/;
  }
}

2、将请求头信息维护到Nacos

如果将请求头信息和一些unknow都是写死在代码中的,不方便后期的维护,这里将可能涉及到请求头基于优先级顺序写在Nacos的配置文件中。

# 维护获取客户端IP地址的请求头信息
header: x-forwarded-for,x-real-ip,proxy-client-ip,wl-proxy-client-ip,http-client-ip

相关参数解读:

  • proxy-client-ip:兼容Apache的服务器,请求头中携带真实IP的名称。
  • wl-proxy-client-ip:WebLogic请求头中携带真实IP的名称。
  • http-client-ip:基于其他的代理服务器的方式获取请求头的IP地址

3、编写Java代码,基于请求头获取真实IP地址

以下代码片段为:
获取Nacos配置文件中的请求头信息,基于循环的方式获取真实IP地址。

/**
 * 客户端IP地址的请求头信息,多个用','隔开。
 */
@Value("${headers}")
private String headers;

/**
 * 基于请求头获取信息时,可能获取到的未知信息
 */
private final String UNKNOW = "unknow";

/**
 * 如果是当前请求头获取IP地址,需要截取到第一个','未知
 */
private final String X_FORWARDED_FOR = "x-forwarded-for";

/**
 * 获取客户端真实的IP地址
 * @param req
 * @return
 */
 @GetMapping(value = "/real_ip")
public void getRealIP(HttpServletRequest req) {
    //1. 声明返回的ip地址
    String ip;

    //2. 遍历请求头,并且通过req获取ip地址
    for (String header : headers.split(",")) {
        // 健壮性校验
        if (!StringUtils.isEmpty(header)) {
            // 基于req获取ip地址
            ip = req.getHeader(header);
            // 如果获取到的ip不为null,不为空串,并且不为unknow,就可以返回
            if (!StringUtils.isEmpty(ip) && !UNKNOW.equalsIgnoreCase(ip)) {
                // 判断请求头是否是x-forwarded-for
                if (X_FORWARDED_FOR.equalsIgnoreCase(header) && ip.indexOf(",") > 0) {
                    ip = ip.substring(0,ip.indexOf(","));
                }
                // 打印IP地址
                System.out.println("客户端IP为==="+ip);
            }
        }
    }

    //3. 如果请求头都没有获取到IP地址,直接基于传统的方式获取一个IP
    System.out.println("getRemoteAddr==="+req.getRemoteAddr());
}