在没有网关或者反向代理软件情况下,java里获取客户端ip地址的方法是request.getRemoteAddr()
先解释下http协议和TCP协议:
网页默认是进行http连接了,http协议即超文本传送协议(Hypertext Transfer Protocol ),是工作TCP协议之上的协议
tcp连接需要三次握手,也就是调用底层的socket进行连接确认。而socket连接需要知道通信双方的ip地址和端口才可以进行数据的正确传输。

由上面可以知道request.getRemoteAddr()方法其实就是获取的连接的客户端socket的ip地址。
但如果我们客户端将要发送接口请求先发送到一台代理请求服务器或者网关后,再由他们进行数据请求,
这时我们使用上面的getRemoteAddr()方法获取到了ip地址就是代理请求服务器或网关的ip地址。
而不是真实的客户端ip地址
也就是说通过nginx等反向代理软件时,不能通过这个方法获取客户端真是ip地址。
如真实ip:223.104.1.240 广东省广州市 移动
访问域名www.zwh.com
nginx所在服务器193.112.28.110
这个域名和nginx所在服务器绑定,
客户端访问时,如www.zwh.com/项目名/index.jsp
这个访问了是nginx的80端口,然后nginx再将这个请求重定向到localhost:8080/项目名/index.jsp
而nginx在将请求进行重定向时会在请求头header中增加一个x-forwarded-for信息,用以跟踪原有客户端ip地址和原来客户端请求的服务器地址
存放的就是x-forwarded-for:223.104.1.240

对应java方法来说,request.getRemoteAddr(),因为直接请求的客户端是nginx,在同一服务器上,所以这个方法获取到的ip地址是127.0.0.1或者193.112.28.110

要获取真实ip地址就要使用request.getHeader("x-forwarded-for")获取请求头部真实ip地址
,但是当xxx.conf配置server节点时,forwarded_for设置为off,则X-Forwarded-For:unknown
默认forwarded_for是on
先看下nginx的部分配置
location / {proxy_redirect off;proxy_pass  http://localhost:8080;proxy_set_header  Host $host;proxy_set_header   X-real-ip $remote_addr;proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;}

src="//common.cnblogs.com/images/copycode.gif" alt=“复制代码”>

继续使用上面数据

这个$host 其实是nginx服务器本身的ip地址:193.112.28.110
$remote_addr这个地址是想nginx请求的客户端地址:223.104.1.240
$proxy_add_x_forwarded_for 这个变量和remote_addr的区别是
proxy_add_x_forwarded_for会将经过的所有代理ip相加起来,
remote_addr则只是获取到直接连接到nginx的ip地址
  在有多个代理服务器的情况下,会将代理服务器的X-Forwarded-For头部的ip地址和客户端的ip地址相加,即:X-Forwarded-For请求头部header的ip字符串  + 直接向nginx服务器发送请求的客户端地址换个表达请求的过程是client--->nginx1--->nginx2---->tomcat而假设client:ip1, nginx1:ip2, nginx2:ip3, tomcat:ip4那么请求request到tomcat时,请求头部header中的X-Forwarded-For信息是=ip1,ip2,ip3

简单了方法

public String getIpAddr(HttpServletRequest request) {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.getRemoteAddr();}return ip;
}

上面三个请求头,大部分的代理或者网关都会加上x-forwarded-for:clientip,proxy1ip,proxy2ip

Proxy-Client-IP这个一般是apache,http服务器才会有,经过apache代理时,apache会在请求头加上x-forwarded-for和Proxy-Client-IP

WL-Proxy-Client-IP这个一般是weblogic才会加上的头部

注意:

1、这些请求头都不是http协议里的标准请求头,也就是说这个是各个代理服务器自己规定的表示客户端地址的请求头。如果哪天有一个代理服务器软件用oooo-client-ip这个请求头代表客户端请求,那上面的代码就不行了。

2、这些请求头不是代理服务器一定会带上的,网络上的很多匿名代理就没有这些请求头,所以获取到的客户端ip不一定是真实的客户端ip。代理服务器一般都可以自定义请求头设置。

3、即使请求经过的代理都会按自己的规范附上代理请求头,上面的代码也不能确保获得的一定是客户端ip。不同的网络架构,判断请求头的顺序是不一样的。

4、最重要的一点,请求头都是可以伪造的。如果一些对客户端校验较严格的应用(比如投票)要获取客户端ip,应该直接使用ip = request.getRemoteAddr (),虽然获取到的可能是代理的ip而不是客户端的ip,但这个获取到的ip基本上是不可能伪造的,也就杜绝了刷票的可能。(有分析说arp欺骗+syn有可能伪造此ip,如果真的可以,这是所有基于TCP协议都存在的漏洞),这个ip是tcp连接里的ip。
IP工具类 import javax.servlet.http.HttpServletRequest; /** * IP地址工具类 * @author xudongdong * */ public class IpUtil {

/*** 私有化构造器*/
private IpUtil() {
}
/*** 获取真实IP地址* <p>使用getRealIP代替该方法</p>* @param request req* @return ip*/
@Deprecated
public static String getClinetIpByReq(HttpServletRequest request) {// 获取客户端ip地址String clientIp = request.getHeader("x-forwarded-for");if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {clientIp = request.getHeader("Proxy-Client-IP");}if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {clientIp = request.getHeader("WL-Proxy-Client-IP");}if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {clientIp = request.getRemoteAddr();}/** 对于获取到多ip的情况下,找到公网ip.*/String sIP = null;if (clientIp != null && !clientIp.contains("unknown") && clientIp.indexOf(",") > 0) {String[] ipsz = clientIp.split(",");for (String anIpsz : ipsz) {if (!isInnerIP(anIpsz.trim())) {sIP = anIpsz.trim();break;}}/** 如果多ip都是内网ip,则取第一个ip.*/if (null == sIP) {sIP = ipsz[0].trim();}clientIp = sIP;}if (clientIp != null && clientIp.contains("unknown")){clientIp =clientIp.replaceAll("unknown,", "");clientIp = clientIp.trim();}if ("".equals(clientIp) || null == clientIp){clientIp = "127.0.0.1";}return clientIp;
}/*** 判断IP是否是内网地址* @param ipAddress ip地址* @return 是否是内网地址*/
public static boolean isInnerIP(String ipAddress) {boolean isInnerIp;long ipNum = getIpNum(ipAddress);/**   私有IP:A类  10.0.0.0-10.255.255.255   B类  172.16.0.0-172.31.255.255   C类  192.168.0.0-192.168.255.255   当然,还有127这个网段是环回地址   **/long aBegin = getIpNum("10.0.0.0");long aEnd = getIpNum("10.255.255.255");long bBegin = getIpNum("172.16.0.0");long bEnd = getIpNum("172.31.255.255");long cBegin = getIpNum("192.168.0.0");long cEnd = getIpNum("192.168.255.255");isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)|| ipAddress.equals("127.0.0.1");return isInnerIp;
}
private static long getIpNum(String ipAddress) {String[] ip = ipAddress.split("\\.");long a = Integer.parseInt(ip[0]);long b = Integer.parseInt(ip[1]);long c = Integer.parseInt(ip[2]);long d = Integer.parseInt(ip[3]);return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
}private static boolean isInner(long userIp, long begin, long end) {return (userIp >= begin) && (userIp <= end);
}
public static String getRealIP(HttpServletRequest request){// 获取客户端ip地址String clientIp = request.getHeader("x-forwarded-for");if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {clientIp = request.getRemoteAddr();}String[] clientIps = clientIp.split(",");if(clientIps.length <= 1) return clientIp.trim();// 判断是否来自CDNif(isComefromCDN(request)){if(clientIps.length>=2) return clientIps[clientIps.length-2].trim();}return clientIps[clientIps.length-1].trim();
}
private static boolean isComefromCDN(HttpServletRequest request) {String host = request.getHeader("host");return host.contains("www.189.cn") ||host.contains("shouji.189.cn") || host.contains("image2.chinatelecom-ec.com") || host.contains("image1.chinatelecom-ec.com");
}

}

java服务端获取客户端ip(代理)相关推荐

  1. 服务端获取客户端ip方法

    X-Forwarded-For X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项.它不是RFC中 ...

  2. springboot实现SSE服务端主动向客户端推送数据,java服务端向客户端推送数据,kotlin模拟客户端向服务端推送数据

    SSE服务端推送 服务器向浏览器推送信息,除了 WebSocket,还有一种方法:Server-Sent Events(以下简称 SSE).本文介绍它的用法. 在很多业务场景中,会涉及到服务端向客户端 ...

  3. Java服务端和客户端开发辅助工具Utils

    包括了各种工具类.辅助类.管理类等 Awesome_API: https://github.com/marktony/Awesome_API/blob/master/Chinese.md 收集中国国内 ...

  4. Java服务端向客户端写文件_java实现客户端向服务器发送文件

    本文实例为大家分享了java实现客户端向服务器发送文件的具体代码,供大家参考,具体内容如下 服务器源代码: import java.io.BufferedReader; import java.io. ...

  5. JAVA 服务端模拟客户端请求http/https

    涉及的包:httpcore-4.3.1.jar,httpclient-4.3.2.jar,httpmime-4.3.2.jar,htmlparser.jar,htmllexer.jar /*  */ ...

  6. BUG记录-Java服务端获取不到请求头里的token

    程序移植到生产环境发生了点问题,app反映token一直过期,我查了查放在请求头里的token没有获取到 String accessToken = request.getHeader(OAUTH_BE ...

  7. java 服务端 获取接收微信小程序wx.uploadFile的formData的值和上传的文件

    小程序前端上传文件的js代码 wx.uploadFile({url: 'https://xxxx',//这是你自己后台的连接filePath: tempFilePath,name:"file ...

  8. java 公网ip_JAVA获取公网ip

    在ipv4地址稀缺的今天,分配到公网ip几乎是不可能的,但是我拨号之后的ip竟然是公网IP. 将自己的电脑作为服务器·,做点好玩的程序,就成为了可能. 由于运营商的ip是动态分配的公网ip的所以就需要 ...

  9. 基于TCP/IP协议的Java服务端与Android客户端的Socket通信及数据交互

    基于TCP/IP协议的Java服务端与Android客户端的Socket通信及数据交互 一.前言 1.Java服务端程序代码的项目名为TcpSocketServerOfJava,包名为com.exam ...

最新文章

  1. 学生籍贯信息管理系统c语言,学生籍贯信息管理系统(c).doc
  2. 易创课堂深圳干货,趁热下载
  3. Python的列表List常见操作
  4. 作者:赵晨(1980-),男,深圳般若计算机系统股份有限公司气象大数据应用负责人...
  5. 基于SSD1306的OLED的驱动学习(二):SSD1306的寻址方式
  6. 麻木的IT公民:293个公司人压力和心理调查
  7. 移动硬盘与电脑连接后 计算机中找不到,移动硬盘连接电脑后不显示盘符怎么办...
  8. windows IIS+php配置教程
  9. 基于java蜗牛兼职网计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  10. IMDB数据看影响电影票房的因素分析
  11. Android Runtime.getRuntime().exec()
  12. macOS 切换python版本
  13. Win10系统繁体字输入切换为简体字快捷键
  14. 计算机知识怎么做框架,计算机基础知识框架.ppt
  15. Python爬虫实战 | (16) 破解简书登录点触验证码
  16. STM32CubeMX之FMC同时挂载SDRAM(W9825G6KH)和TFTLCD
  17. 不太简单的简单逆向24(xxtea)
  18. 通过ContentProvider实现获取手机联系人
  19. 易能机器人_江西全新台达机器人
  20. java实现漏掉的账目明细

热门文章

  1. 数据访问层(连接数据库)
  2. github remote: Support for password authentication was removed on August 13, 2021.
  3. 通过ssh进行远程访问
  4. Python 模板 Jinja2
  5. 能量原理与变分法笔记17:广义变分原理(识别因子方法)
  6. Lightwave 3D 8 Cartoon Character Creation, Volume 1: Modeling Texturing
  7. 【SPSS】利用spss进行图斑数据统计
  8. 《学会提问》——逻辑谬误初识
  9. 小程序人像卡通化(Java)(模板使用)
  10. 漫画:什么是选择排序?