在后端 JAVA 通过以下代码
private String getRemoteHost(HttpServletRequest request) {
// 查看请求头中的所有信息
final Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
final String nextName = headerNames.nextElement();
System.out.println(nextName + "=" + request.getHeader(nextName));
}
// 需要在 nginx 代理商设置 proxy_set_header REMOTE-HOST $remote_addr;
final String header = request.getHeader("remote-host");
if (header != null) {
return header;
}
return request.getRemoteHost();
}
nginx 代理配置如下
location ^~ /api/ {
rewrite /api/(.*) /$1 break;
proxy_pass http://host-api;
client_max_body_size 500M;
proxy_set_header Host $host;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Real-IP $remote_addr:$remote_port;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
在上述配置中,各种配置都加了,但是获取到的始终是 docker 容器的 IP,查看 nginx 访问日志
192.168.0.29 - - [06/Jul/2021:09:55:40 +0000] "POST /api/account/search HTTP/1.0" 200 4794 "https://mrcode.com/auth/account" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36" "110.110.106.50"
如上所示,最前面的 IP 就是就是 $remote_addr
,的确是容器的 IP,无论咋折腾都没有效果,改动不了这个,然后看了下 nginx 日志格式
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
最后一个字段 $http_x_forwarded_for
是日志中看到的 IP (日志最后)的含义,这个 IP 是真实的客户端 IP,修改下代理配置
# proxy_set_header REMOTE-HOST $remote_addr;
# 修改成最后一个字段
proxy_set_header REMOTE-HOST $http_x_forwarded_for;
总结:不一定要放到 remote-host 上面,只要拿到真实 IP,可以放到任意的一个 header 上面,那么后端的 java 应用就不需要做额外的代码处理了。
那么为什么真实 IP 会出现在 http_x_forwarded_for 头中呢?这个就要看看一个客户端请求到达你服务器经过了哪些代理转发?我遇到这个就是前面还有一个域名转发的服务器