Java获取客户端IP[通俗易懂]

转载地址:Java获取客户端IP 在开发工作中,我们常常需要获取客户端的IP。一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。原因:由于在客户端和服务之间增加了中间代理,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。现在图示代理上网和I

大家好,又见面了,我是全栈君。

转载地址:Java获取客户端IP
这里虽然是转载的博文,在看博文之前先说明一下,如果你使用的是公司的内网访问,那么对外的出口可能只有一个或者几个,那么客户端的IP就有可能两个人获取的同样的IP!
在开发工作中,我们常常需要获取客户端的IP。一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

原因:由于在客户端和服务之间增加了中间代理,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。

现在图示代理上网和IP的关系:
这里写图片描述
第二种情况:通过代理服务器如:Nginx,Squid等一层代理或多层代理上网,如下图:
这里写图片描述
需要注意的是X-Forwarded-For和X-Real-IP都不是http的正式协议头,而是squid等反向代理软件最早引入的,之所以resin能拿到,是因为NGINX里一般缺省都会这么配置转发的http请求:

location / {

         proxy_pass       http://yourdomain.com;

         proxy_set_header   Host             $host;

         proxy_set_header   X-Real-IP        $remote_addr;

         proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

         }

从X-Forwarded-For的定义来看,ips[0]才是原始客户端ip,如果这个都不是,那拿第二个就更不靠谱了,我们平时检验的时候,可能是直接在内网挂代理去访问的,跟外面网友访问经过的网络路径不一样,后面不停添加的是经过的每一层代理ip才对,下面举例说明;

request.getRemoteAddr() 192.168.239.196

request.getHeader(“X-Forwarded-For”) 58.63.227.162, 192.168.237.178, 192.168.238.218

request.getHeader(“X-Real-IP”) 192.168.238.218

所以访问的流程应该是这样,客户端58.63.227.162发出请求,经过192.168.237.178, 192.168.238.218两层转发,到了192.168.239.196这台NGINX上,NGINX就把X-Real-IP头设成了自己看到的remote_addr,也就是直接发给到他的192.168.238.218,这时候resin收到这个包,对resin来说直接发给他的remote_addr就是NGINX的ip,也就是192.168.239.196,那么resin里面的request.getRemoteAddr()就是192.168.239.196,那么在resin里拿最原始的ip逻辑(也就是拿能够知道的最外层的ip)应该是这样:

        如果XFF不为空,拿XFF的左边第一个

        如果XFF为空,拿XRI

        如果XRI为空,只能拿request.getRemoteAddr(),也就是只能拿到最直接发给他的机器ip了,

其他都不可考究,参考代码如下:

第一种代码:

/** * 从Request对象中获得客户端IP,处理了HTTP代理服务器和Nginx的反向代理截取了ip * @param request * @return ip */
    public static String getLocalIp(HttpServletRequest request) {
        String remoteAddr = request.getRemoteAddr();
        String forwarded = request.getHeader("X-Forwarded-For");
        String realIp = request.getHeader("X-Real-IP");

        String ip = null;
        if (realIp == null) {
            if (forwarded == null) {
                ip = remoteAddr;
            } else {
                ip = remoteAddr + "/" + forwarded.split(",")[0];
            }
        } else {
            if (realIp.equals(forwarded)) {
                ip = realIp;
            } else {
                if(forwarded != null){
                    forwarded = forwarded.split(",")[0];
                }
                ip = realIp + "/" + forwarded;
            }
        }
        return ip;
    }

第二种代码:

public static String getIp(HttpServletRequest request) {
        String remoteAddr = request.getRemoteAddr();
        String forwarded = request.getHeader("X-Forwarded-For");
        String realIp = request.getHeader("X-Real-IP");

        String ip = null;
        if (realIp == null) {
            if (forwarded == null) {
                ip = remoteAddr;
            } else {
                ip = remoteAddr + "/" + forwarded;
            }
        } else {
            if (realIp.equals(forwarded)) {
                ip = realIp;
            } else {
                ip = realIp + "/" + forwarded.replaceAll(", " + realIp, "");
            }
        }
        return ip;
    }

第三种代码:

public static String getIp2(HttpServletRequest request) {
           String ip = request.getHeader("X-Forwarded-For");
           if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
               //多次反向代理后会有多个ip值,第一个ip才是真实ip
               int index = ip.indexOf(",");
               if(index != -1){
                   return ip.substring(0,index);
               }else{
                   return ip;
               }
           }
           ip = request.getHeader("X-Real-IP");
           if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){
               return ip;
           }
           return request.getRemoteAddr();
       }

第三种是最合适的,最清晰理解的!

附两个方法:也是从其他地方看到的,记录下来,方便以后学习!

/** * 通过HttpServletRequest返回IP地址 * @param request HttpServletRequest * @return ip String * @throws Exception */
public String getIpAddr(HttpServletRequest request) throws Exception {
    String ip = request.getHeader("x-forwarded-for");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("HTTP_CLIENT_IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
    return ip;
}



 /** * 通过IP地址获取MAC地址 * @param ip String,127.0.0.1格式 * @return mac String * @throws Exception */
public String getMACAddress(String ip) throws Exception {
    String line = "";
    String macAddress = "";
    final String MAC_ADDRESS_PREFIX = "MAC Address = ";
    final String LOOPBACK_ADDRESS = "127.0.0.1";
    //如果为127.0.0.1,则获取本地MAC地址。
    if (LOOPBACK_ADDRESS.equals(ip)) {
        InetAddress inetAddress = InetAddress.getLocalHost();
        //貌似此方法需要JDK1.6。
        byte[] mac = NetworkInterface.getByInetAddress(inetAddress).getHardwareAddress();
        //下面代码是把mac地址拼装成String
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            //mac[i] & 0xFF 是为了把byte转化为正整数
            String s = Integer.toHexString(mac[i] & 0xFF);
            sb.append(s.length() == 1 ? 0 + s : s);
        }
        //把字符串所有小写字母改为大写成为正规的mac地址并返回
        macAddress = sb.toString().trim().toUpperCase();
        return macAddress;
    }
    //获取非本地IP的MAC地址
    try {
        Process p = Runtime.getRuntime().exec("nbtstat -A " + ip);
        InputStreamReader isr = new InputStreamReader(p.getInputStream());
        BufferedReader br = new BufferedReader(isr);
        while ((line = br.readLine()) != null) {
            if (line != null) {
                int index = line.indexOf(MAC_ADDRESS_PREFIX);
                if (index != -1) {
                    macAddress = line.substring(index + MAC_ADDRESS_PREFIX.length()).trim().toUpperCase();
                }
            }
        }
        br.close();
    } catch (IOException e) {
        e.printStackTrace(System.out);
    }
    return macAddress;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/121232.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • web网络聊天室

    web网络聊天室花了四天时间做了一个简单的web聊天室前端页面效果大概是下面这个样子1.登陆界面2.注册界面这里首先会检查用户名是否重复,如果重复,会提示你用户名已存在反正显示可用3.聊天室界面登陆成功会在左边显示登陆人的名称以及当前在线人数。然后在下面可用选择对谁说以及一些文字表情,字体颜色什么的4.聊天功能会显示发送者名称,以及对谁说,语气词,以及发送时间最后总结一下做的…

  • RPN网络解读

    RPN网络解读RPN网络源码解读在高层的featuremap初次计算anchorbox点数值604099代表一个特征维度生成9个anchorbox,但特征层w,h为啥是60,40不应该是相等的?毕竟backbone网络一系列操作(下采样),w,h同时缩小的。下不管了,不是今天主要问题。step1:也就是说原始生成大约20000boxs,再进行2k排序(每个boxs得分为目标或背景的概率,不管是背景还是目标都要得分高的)设定阈值为12000,也就是说最多保留12000,也有的源码设定2000。step2

  • Alex 的 Hadoop 菜鸟教程: 第3课 Hadoop 安装教程 – 非HA方式 (一台服务器)「建议收藏」

    Alex 的 Hadoop 菜鸟教程: 第3课 Hadoop 安装教程 – 非HA方式 (一台服务器)「建议收藏」本教程是在Centos6下使用yum来安装CDH5版本的hadoop的教程,适合新手并且只有一个linux服务器的情况下最快速度的上手hadoop

  • 美丽的表格样式(使用CSS样式表控制表格样式)

    美丽的表格样式(使用CSS样式表控制表格样式)

  • matlab如何使用random函数,random函数

    matlab如何使用random函数,random函数手机评站网今天精心准备的是《random函数》,下面是详解!random函数的用法是turbopascal中的函数,希望有具体的介绍(有程序最好)…是turbopascal中的函数,希望有具体的介绍(有程序最好)用法:1、随机生成(0,1)之间的浮点数random.random()2、随机生成100-200的整数random.randint(100,200)3、随机产生范围为10间隔为2的…

  • ubuntu下rabbitvcs安装后无右键菜单解决办法

    ubuntu下rabbitvcs安装后无右键菜单解决办法1、sudorabbitvcs2、rabbitvcs3、nautilus-q4、ls-ldxxx/RabbitVCS.logsudochown-R’currentuser’xxx/RabbitVCS.log

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号