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获取客户端信息存在问题,那我们该如何解决这个问题呢?
我们整体上需要从两个方面来解决这些问题:
(1)由于Nginx是代理服务器,所有客户端请求都从Nginx转发到Jetty/Tomcat,如果Nginx不把客户端真实IP、域名、协议、端口告诉Jetty/Tomcat,那么Jetty/Tomcat应用永远不会知道这些信息,所以需要Nginx配置一些HTTP Header来将这些信息告诉被代理的Jetty/Tomcat;
(2)Jetty/Tomcat这一端,不能再获取直接和它连接的客户端(也就是Nginx)的信息,而是要从Nginx传递过来的HTTP Header中获取客户端信息。
配置nginx
首先,我们需要在Nginx的配置文件nginx.conf中添加如下配置。
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;
各参数的含义如下所示。
-
Host
包含客户端真实的域名和端口号; -
X-Forwarded-Proto
表示客户端真实的协议(http还是https); -
X-Real-IP
表示客户端真实的IP; -
X-Forwarded-For
这个Header和X-Real-IP
类似,但它在多层代理时会包含真实客户端及中间每个代理服务器的IP。
此时,再试一下request.getRemoteAddr()
和request.getRequestURL()
的输出结果:
RemoteAddr: 127.0.0.1
URL: http://192.168.1.100/test
可以发现URL好像已经没问题了,但是IP还是本地的IP而非真实客户端IP。但是如果是用Nginx作为https服务器反向代理到http服务器,会发现浏览器地址栏是https前缀但是request.getRequestURL()
获取到的URL还是http前缀,也就是仅仅配置Nginx还不能彻底解决问题。
通过Java方法获取客户端信息
仅仅配置Nginx不能彻底解决问题,那如何才能解决这个问题呢?一种解决方式就是通过Java方法获取客户端信息,例如下面的Java方法。
/***
- 获取客户端IP地址;这里通过了Nginx获取;X-Real-IP
*/
public static String getClientIP(HttpServletRequest request) {
String fromSource = “X-Real-IP”;
String ip = request.getHeader(“X-Real-IP”);
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getHeader(“X-Forwarded-For”);
fromSource = “X-Forwarded-For”;
}
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getHeader(“Proxy-Client-IP”);
fromSource = “Proxy-Client-IP”;
}
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getHeader(“WL-Proxy-Client-IP”);
fromSource = “WL-Proxy-Client-IP”;
}
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
fromSource = “request.getRemoteAddr”;
}
return ip;
}
这种方式虽然能够获取客户端的IP地址,但是我总感觉这种方式不太友好,因为既然Servlet API提供了request.getRemoteAddr()
方法获取客户端IP,那么无论有没有用反向代理对于代码编写者来说应该是透明的。
接下来,我就分别针对Jetty服务器和Tomcat服务器为大家介绍下如何进行配置才能更加友好的获取客户端信息。
Jetty服务器
在Jetty服务器的jetty.xml文件中,找到httpConfig
,加入配置:
…
重新启动Jetty,再用浏览器打开http://192.168.1.100/test测试,结果:
RemoteAddr: 192.168.1.100
URL: http://192.168.1.100/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
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
权威指南-第一本Docker书
引领完成Docker的安装、部署、管理和扩展,让其经历从测试到生产的整个开发生命周期,深入了解Docker适用于什么场景。并且这本Docker的学习权威指南介绍了其组件的基础知识,然后用Docker构建容器和服务来完成各种任务:利用Docker为新项目建立测试环境,演示如何使用持续集成的工作流集成Docker,如何构建应用程序服务和平台,如何使用Docker的API,如何扩展Docker。
总共包含了:简介、安装Docker、Docker入门、使用Docker镜像和仓库、在测试中使用Docker、使用Docker构建服务、使用Fig编配Docke、使用Docker API、获得帮助和对Docker进行改进等9个章节的知识。
关于阿里内部都在强烈推荐使用的“K8S+Docker学习指南”—《深入浅出Kubernetes:理论+实战》、《权威指南-第一本Docker书》,看完之后两个字形容,爱了爱了!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
713533956795)]
[外链图片转存中…(img-bIT0ggoU-1713533956799)]
关于阿里内部都在强烈推荐使用的“K8S+Docker学习指南”—《深入浅出Kubernetes:理论+实战》、《权威指南-第一本Docker书》,看完之后两个字形容,爱了爱了!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!