本文基于方法 HttpServletRequest.getHeader 和 HttpServletRequest.getRemoteAddr 介绍如何在服务器端获取客户端真实IP地址。

业务背景

服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等拦截,在进行IP限定的时候就需要获取客户端真实的IP。

基础知识

 
      访问服务端的方式一般分为两种:
  • 未经过代理,直接访问服务器端;
  • 通过多级代理,最终到达服务器端(nginx,squid,haproxy)。
      客户端请求信息都包含在HttpServletRequest中,对于第一种访问方式可以通过getRemoteAddr()方法获得客户端真实IP,而另一种则行不通,但是可以通过x-forwarded-for获得转发后请求信息。当客户端请求被转发时,IP将会追加在其后并以英文逗号隔开,例如:10.47.103.13,4.2.2.2,10.96.112.230。
请求中的参数:
  request.getHeader("x-forwarded-for") : 10.47.103.13,4.2.2.2,10.96.112.230
  request.getHeader("X-Real-IP") : 10.47.103.13
  request.getRemoteAddr():10.96.112.230

客户端访问经过转发,IP将会追加在其后并以逗号隔开。最终准确的客户端信息为:

  • x-forwarded-for 不为空,则为逗号前第一个IP ;
  • X-Real-IP不为空,则为该IP ;
  • 否则为getRemoteAddr() ;
       相关请求头的解释:
       X-Forwarded-For 记录一个请求从客户端出发到目标服务器过程中经历的代理,或者负载平衡设备的IP。这是由缓存代理软件 Squid 引入,用来表示 HTTP 请求端真实 IP,现在已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。格式为X-Forwarded-For:client1,proxy1,proxy2,一般情况下,第一个ip为客户端真实ip,后面的为经过的代理服务器的ip。现在大部分的代理都会加上这个请求头。
       Proxy-Client-IP/WL- Proxy-Client-IP 这个一般是经过apache http服务器的请求才会有,用apache http做代理时一般会加上Proxy-Client-IP请求头,而WL-Proxy-Client-IP是他的weblogic插件加上的头。
       HTTP_CLIENT_IP  有些代理服务器会加上此请求头。
      X-Real-IP nginx代理一般会加上此请求头。

获取客户端真实IP地址

源码:

/**
* 获取客户端的IP地址<br/>
* 注意本地测试访问项目地址时,浏览器请求不要用 localhost,请用本机IP;否则,取不到 IP
*
* @author east7
* @date 2019年12月03日
* @return String 真实IP地址
*/
public static String getClientIpAddress(HttpServletRequest request) {
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
String headerName = "x-forwarded-for";
String ip = request.getHeader(headerName);
if (null != ip && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个IP值,第一个IP才是真实IP,它们按照英文逗号','分割
if (ip.indexOf(",") != -1) {
ip = ip.split(",")[0];
}
}
if (checkIp(ip)) {
headerName = "Proxy-Client-IP";
ip = request.getHeader(headerName);
}
if (checkIp(ip)) {
headerName = "WL-Proxy-Client-IP";
ip = request.getHeader(headerName);
}
if (checkIp(ip)) {
headerName = "HTTP_CLIENT_IP";
ip = request.getHeader(headerName);
}
if (checkIp(ip)) {
headerName = "HTTP_X_FORWARDED_FOR";
ip = request.getHeader(headerName);
}
if (checkIp(ip)) {
headerName = "X-Real-IP";
ip = request.getHeader(headerName);
}
if (checkIp(ip)) {
headerName = "remote addr";
ip = request.getRemoteAddr();
// 127.0.0.1 ipv4, 0:0:0:0:0:0:0:1 ipv6
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
//根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ip = inet.getHostAddress();
}
}
logger.info("getClientIp IP is " + ip + ", headerName = " + headerName);
return ip;
}
private static boolean checkIp(String ip) {
if (null == ip || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
return true;
}
return false;
}

Java 获取客户端真实IP地址的更多相关文章

  1. Java获取客户端真实IP地址的两种方法

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  2. Java获取客户端真实IP地址

    Java代码 import javax.servlet.http.HttpServletRequest; /** * 获取对象的IP地址等信息 */ public class IPUtil { /** ...

  3. Nginx反向代理后,java获取客户端真实IP地址

    一般情况下,java获取客户端IP地址的方法为request.getRemoteAddr();但这只是在没有网关或者代理的情况下,如果客户端将请求发送到nginx,再由nginx进行反向代理到目标服务 ...

  4. 伪造IP及获取客户端真实IP地址

    Fiddler支持自定义规则,可以实现对HTTP请求数据发送给Server前或HTTP应答数据发送给浏览器前进行修改.下面的例子将演示如何向所有HTTP请求数据中增加一个头.1)打开Fiddler,点 ...

  5. 获取客户端真实IP地址

    Java-Web获取客户端真实IP: 发生的场景:服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等情况,在进行客户端IP限定的时候,需要首先获取该真实的IP. 一般分为两种情况: ...

  6. 【整理】PHP获取客户端真实IP地址详解

    php获取客户端IP地址有四种方法,这五种方法分别为REMOTE_ADDR.HTTP_CLIENT_IP.HTTP_X_FORWARDED_FOR.HTTP_VIA. REMOTE_ADDR 是你的客 ...

  7. java 获取客户端的ip地址

    import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHo ...

  8. java获取客户端请求IP地址(公网ip)

    之前写了一个获取ip地址的方法,但是放网上一查显示此Ip地址是局域网ip地址,要是想获取请求端的真实公网ip地址怎么样了,看了一些别人的博客后发现,想要获取客户端的公网ip必须借助第三方. packa ...

  9. Java获取客户端真实IP

    一般情况下,我们可以使用 request 的 getRemoteAddr()  方法获取客户端实际 IP ,但是使用反向代理后,我们使用 getRemoteAddr() 是无法获取真实的  IP 的. ...

随机推荐

  1. glfw内存泄露测试

    1. glfwInit()   和  glfwTerminate()  放在主线程  循环次数 1    内存   14M 循环次数100    46M 循环次数1000   49M 2.  glfw ...

  2. 【转载】C#中可使用string.Empty代表空字符

    在C#中,如果赋值一个字符串为空白字符串,我们一般会用“”的形式对字符串进行赋值操作,其实在C#的字符串类String类中,有个专门的常量string.Empty来代表空字符串,可直接在赋值的时候使用 ...

  3. 【English】 Re-pick up English for learning big data (not updated regularly)

    2019.10.6 parse:解析mean:平均数stddev:标准偏差 2019.10.7 bigdata platform:大数据平台 2019.10.14 allocate resource ...

  4. api markdown 编排模版

    #### 简要描述: - 查询城市编码 #### 接口版本: |版本号|制定人|制定日期|修订日期||:---- |:------ |:-------- |------- ||1.0 |XXX|201 ...

  5. QT--初识

    一.组成QT的基本模块 二.创建一个简单工程 1.工程结构介绍 .pro 文件 QT += core gui # 包含的模块 greaterThan(QT_MAJOR_VERSION, ): QT + ...

  6. jQuery + ashx 实现图片按比例预览、异步上传及显示

    目录(?)[-] 注ajax 方式异步读取数据库显示图片的方法同上传一致使用 ashx 返回base64字符串在客户端处理即可 记录一个让我纠结良久的问题 在Page_Load 函数中只有第一个用 S ...

  7. docker 运行ELK

    docker network create somenetwork docker run -d --name elasticsearch --net somenetwork -p 9200:9200 ...

  8. 微信小程序~App.js中获取用户信息

    (1)代码:主要介绍下获取用户信息部分 onLaunch: function () { // 展示本地存储能力 var logs = wx.getStorageSync('logs') || [] l ...

  9. 《代码敲不队》第九次团队作业:Beta冲刺第2天

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 代码敲不队 作业学习目标 (1)项目文档的完善与整理:(2)团队项目总结陈述PPT编制:(3)符合 ...

  10. 什么是好的产品——Diet Rams的十大设计原则

    博朗(BRAUN)的首席设计师Diet Rams的十大设计原则 第一条,好的产品是有创意的,它必须是一个创新的东西: 第二条,好的产品是有用的,一定要对人有用: 第三条,好的产品是优美的,它必须有美感 ...