原创

记一次Nginx配置错误,Java获取不到IP地址的经历

温馨提示:
本文最后更新于 2019年10月21日,已超过 1,859 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

Java获取IP地址

在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。

是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿到客户端的 IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。

方法1

/** 
 * 获取当前网络ip 
 * @param request 
 * @return 
 */  
public String getIpAddr(HttpServletRequest request){  
  String ipAddress = request.getHeader("x-forwarded-for");  
  if(ipAddress==null||ipAddress.length()== 0||"unknown".equalsIgnoreCase(ipAddress)){  
       ipAddress=request.getHeader("Proxy-Client-IP");  
   }  
  if(ipAddress==null||ipAddress.length()== 0||"unknown".equalsIgnoreCase(ipAddress)){  
       ipAddress = request.getHeader("WL-Proxy-Client-IP");  
    }  
  if(ipAddress==null||ipAddress.length()== 0||"unknown".equalsIgnoreCase(ipAddress)){  
       ipAddress = request.getRemoteAddr();  
  if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){  
         /*根据网卡取本机配置的IP  */
      InetAddress inet=null;  
          try {  
              inet = InetAddress.getLocalHost();  
          } catch (UnknownHostException e) {  
              e.printStackTrace();  
        }  
           ipAddress= inet.getHostAddress();  
       }  
     }  
       /*对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割  */
     if(ipAddress!=null && ipAddress.length()>15){ /*"***.***.***.***".length() = 15*/
        if(ipAddress.indexOf(",")>0){  
             ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));  
            }  
        }  
     return ipAddress;   
}

方法2

package com.lzhpo.utils;

import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

/**
 * 获取IP的工具类
 *
 * @author lzhpo
 * @version 1.0
 * @website http://www.lzhpo.com
 * @date 2018/4/18 11:48
 * @since 1.0
 */
public class IpUtil {

    /**
     * 获取真实IP
     *
     * @param request
     * @return
     */
    public static String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        return checkIp(ip) ? ip : (
                checkIp(ip = request.getHeader("Proxy-Client-IP")) ? ip : (
                        checkIp(ip = request.getHeader("WL-Proxy-Client-IP")) ? ip :
                                request.getRemoteAddr()));
    }
    /**
     * 校验IP
     *
     * @param ip
     * @return
     */
    private static boolean checkIp(String ip) {
        return !StringUtils.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip);
    }

}

方法3

简单粗暴。

public String getRemortIP(HttpServletRequest request) {  
    if (request.getHeader("x-forwarded-for") == null) {  
        return request.getRemoteAddr();  
    }  
    return request.getHeader("x-forwarded-for");  
}

But

这两种方式其实都是一样的,只是方法2封装的好看一点。

我配置的Nginx都是获取不到用户真实IP。

比如:我访问我的博客www.lzhpo.com,我使用了代理工具Nginx,访问过程如下:

www.lzhpo.com => 我的服务器IP地址 => 获取用户访问的真实IP

所以,如果是直接是在我域名的情况下获取的IP是我的服务器的IP,而不是真实用户的IP,因为我Nginx以及反向代理到了我的服务器IP。

配置Nginx,还是拿我的博客www.lzhpo.com为例:

server {
         listen 80;
        server_name www.lzhpo.com;
         location / {
            proxy_pass http://47.106.236.228:8443;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         }
    }

意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。

我就是因为没加上proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;导致获取不到用户访问的IP地址,无法定位。

那么$proxy_add_x_forwarded_for又是什么?

$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。

题外话

配合百度地图开放平台)食用,效果更佳~

本文目录