Nginx+Tomcat _ Jetty/Tomcat + Nginx反向代理获取客户端真实IP、域名、协议、端口

本文主要是介绍Nginx+Tomcat _ Jetty/Tomcat + Nginx反向代理获取客户端真实IP、域名、协议、端口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:

Jetty/Tomcat + Nginx反向代理获取客户端真实IP、域名、协议、端口

https://blog.csdn.net/xiao__gui/article/details/73733797

 

问题


Nginx反向代理后,Servlet应用通过request.getRemoteAddr()取到的IP是Nginx的IP地址,并非客户端真实IP,通过request.getRequestURL()获取的域名、协议、端口都是Nginx访问Web应用时的域名、协议、端口,而非客户端浏览器地址栏上的真实域名、协议、端口。

例如在某一台IP为10.4.64.22的服务器上,Jetty或者Tomcat端口号为8080,Nginx端口号80,Nginx反向代理8080端口:

server {listen 80;location / {proxy_pass http://127.0.0.1:8080; # 反向代理应用服务器HTTP地址}
}



在另一台机器上用浏览器打开http://10.4.64.22/test访问某个Servlet应用,获取客户端IP和URL:

System.out.println("RemoteAddr: " + request.getRemoteAddr());
System.out.println("URL: " + request.getRequestURL().toString());


结果是:

RemoteAddr: 127.0.0.1
URL: http://127.0.0.1:8080/test


可以发现,Servlet程序获取到的客户端IP是Nginx的IP而非浏览器所在机器的IP,获取到的URL是Nginx proxy_pass配置的URL组成的地址,而非浏览器地址栏上的真实地址。如果将Nginx用作https服务器反向代理后端的http服务,那么request.getRequestURL()获取的URL是http前缀的而非https前缀,无法获取到浏览器地址栏的真实协议。如果此时将request.getRequestURL()获取得到的URL用作拼接Redirect地址,就会出现跳转到错误的地址,这也是Nginx反向代理时经常出现的一个问题。

 

问题产生的原因


Nginx的反向代理实际上是客户端和真实的应用服务器之间的一个桥梁,客户端(一般是浏览器)访问Nginx服务器,Nginx再去访问Web应用服务器。对于Web应用来说,这次HTTP请求的客户端是Nginx而非真实的客户端浏览器,如果不做特殊处理的话,Web应用会把Nginx当作请求的客户端,获取到的客户端信息就是Nginx的一些信息。

 

解决方案


解决这个问题要从两个方面来解决: 
1. 由于Nginx是代理服务器,所有客户端请求都从Nginx转发到Jetty/Tomcat,如果Nginx不把客户端真实IP、域名、协议、端口告诉Jetty/Tomcat,那么Jetty/Tomcat应用是永远不会知道这些信息的,所以需要Nginx配置一些HTTP Header来将这些信息告诉被代理的Jetty/Tomcat; 
2. Jetty/Tomcat这一端,不能再傻乎乎的获取直接和它连接的客户端(也就是Nginx)的信息,而是要从Nginx传递过来的HTTP Header中获取客户端信息。

Nginx 添加以下配置:

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;



解释以下上面的配置,以上配置是在Nginx反向代理的时候,添加一些请求Header。

 
1. Host 包含客户端真实的域名和端口号; 
2. X-Forwarded-Proto 表示客户端真实的协议(http还是https); 
3. X-Real-IP 表示客户端真实的IP; 
4. X-Forwarded-For 这个Header和X-Real-IP类似,但它在多层代理时会包含真实客户端及中间每个代理服务器的IP。

再试一下request.getRemoteAddr()request.getRequestURL()的输出结果:

RemoteAddr: 127.0.0.1
URL: http://10.4.64.22/test



可以发现URL好像已经没问题了,但是IP还是本地的IP而非真实客户端IP。但是如果是用Nginx作为https服务器反向代理到http服务器,会发现浏览器地址栏是https前缀但是request.getRequestURL()获取到的URL还是http前缀,也就是仅仅配置Nginx还不能彻底解决问题。

 

Jetty/Tomcat


如果你在网上搜索“Java如何获取客户端真实IP”,搜索到的解决方案大多是通过获取HTTP请求头request.getHeader("X-Forwarded-For")request.getHeader("X-Real-IP")来实现,也就是上面在Nginx上配置的Header,这种方案获取的结果的确是正确的,但是我个人觉得并不优雅。因为既然Servlet API提供了request.getRemoteAddr()方法获取客户端IP,那么无论有没有用反向代理对于代码编写者来说应该是透明的。下面介绍一种更加优雅的方式。

 

Jetty


在Jetty服务器的jetty.xml文件中,找到httpConfig,加入配置:

<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">...<Call name="addCustomizer"><Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg></Call>
</New>



重新启动Jetty,再用浏览器打开http://10.4.64.22/test测试,结果:

RemoteAddr: 10.1.3.7
URL: http://10.4.64.22/test


此时可发现通过request.getRemoteAddr()获取到的IP不再是127.0.0.1而是客户端真实IP,request.getRequestURL()获取的URL也是浏览器上的真实URL,如果Nginx作为https代理,request.getRequestURL()的前缀也会是https。

另外,Jetty将这个功能封装成一个模块:http-forwarded。如果不想改jetty.xml配置文件的话,也可以启用http-forwarded模块来实现。

例如可以通过命令行启动Jetty:

java -jar start.jar --module=http-forwarded


更多Jetty如何启用模块的相关资料可以参考:http://www.eclipse.org/jetty/documentation/current/startup.html

Tomcat


和Jetty类似,如果使用Tomcat作为应用服务器,可以通过配置Tomcat的server.xml文件,在Host元素内最后加入:

<Valve className="org.apache.catalina.valves.RemoteIpValve" />


 

这篇关于Nginx+Tomcat _ Jetty/Tomcat + Nginx反向代理获取客户端真实IP、域名、协议、端口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/956016

相关文章

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细... 目录【1】saveBATch(一万条数据总耗时:2478ms)【2】集合方式foreach(一万条数

python获取网页表格的多种方法汇总

《python获取网页表格的多种方法汇总》我们在网页上看到很多的表格,如果要获取里面的数据或者转化成其他格式,就需要将表格获取下来并进行整理,在Python中,获取网页表格的方法有多种,下面就跟随小编... 目录1. 使用Pandas的read_html2. 使用BeautifulSoup和pandas3.

SpringBoot UserAgentUtils获取用户浏览器的用法

《SpringBootUserAgentUtils获取用户浏览器的用法》UserAgentUtils是于处理用户代理(User-Agent)字符串的工具类,一般用于解析和处理浏览器、操作系统以及设备... 目录介绍效果图依赖封装客户端工具封装IP工具实体类获取设备信息入库介绍UserAgentUtils

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

CentOS7更改默认SSH端口与配置指南

《CentOS7更改默认SSH端口与配置指南》SSH是Linux服务器远程管理的核心工具,其默认监听端口为22,由于端口22众所周知,这也使得服务器容易受到自动化扫描和暴力破解攻击,本文将系统性地介绍... 目录引言为什么要更改 SSH 默认端口?步骤详解:如何更改 Centos 7 的 SSH 默认端口1

C# foreach 循环中获取索引的实现方式

《C#foreach循环中获取索引的实现方式》:本文主要介绍C#foreach循环中获取索引的实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、手动维护索引变量二、LINQ Select + 元组解构三、扩展方法封装索引四、使用 for 循环替代

SpringBoot内嵌Tomcat临时目录问题及解决

《SpringBoot内嵌Tomcat临时目录问题及解决》:本文主要介绍SpringBoot内嵌Tomcat临时目录问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录SprinjavascriptgBoot内嵌Tomcat临时目录问题1.背景2.方案3.代码中配置t

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

springboot上传zip包并解压至服务器nginx目录方式

《springboot上传zip包并解压至服务器nginx目录方式》:本文主要介绍springboot上传zip包并解压至服务器nginx目录方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录springboot上传zip包并解压至服务器nginx目录1.首先需要引入zip相关jar包2.然