反向代理:Nginx (nginx version: nginx/1.14.2)
网关:Zuul (2.2.9.RELEASE)
服务:SpringBoot使用内置Tomcat (9.0.71)
Nginx:设置请求头,向后面的代理或服务传递真实的协议、域名(ip)、端口
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_redirect http:// $scheme://;
Zuul
server.tomcat.remoteip.remote-ip-header=X-Forwarded-For
server.tomcat.remoteip.protocol-header=X-Forwarded-Proto
server.tomcat.remote.port-header=X-Forwarded-Port
server.forward-headers-strategy=native
zuul.add-host-header=true
zuul.add-proxy-headers=false
SpringBoot
server.tomcat.remoteip.remote-ip-header=X-Forwarded-For
server.tomcat.remoteip.protocol-header=X-Forwarded-Proto
server.tomcat.remote.port-header=X-Forwarded-Port
server.forward-headers-strategy=native
server.tomcat.remoteip.internal-proxies=192\.168\.16\.50|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|169\.254\.\d{1,3}\.\d{1,3}|127\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.1[6-9]{1}\.\d{1,3}\.\d{1,3}|172\.2[0-9]{1}\.\d{1,3}\.\d{1,3}|172\.3[0-1]{1}\.\d{1,3}\.\d{1,3}|0:0:0:0:0:0:0:1|::1
1.确认Nginx配置:proxy_set_header X-Forwarded-Proto $scheme;
2.确认SpringBoot配置:server.tomcat.remoteip.protocol-header=X-Forwarded-Proto
3.上面都配置,还不行;去看看代码哪里设置的这个请求头(X-Forwarded-Proto)
类:org/apache/catalina/valves/RemoteIpValve.java
方法:public void invoke(Request request, Response response)
if (protocolHeader != null) {
String protocolHeaderValue = request.getHeader(protocolHeader);
if (protocolHeaderValue == null) {
// Don't modify the secure, scheme and serverPort attributes
// of the request
} else if (isForwardedProtoHeaderValueSecure(protocolHeaderValue)) {
request.setSecure(true);
request.getCoyoteRequest().scheme().setString("https");
setPorts(request, httpsServerPort);
} else {
request.setSecure(false);
request.getCoyoteRequest().scheme().setString("http");
setPorts(request, httpServerPort);
}
}
前提条件:
final String originalRemoteAddr = request.getRemoteAddr();
boolean isInternal = internalProxies != null &&
internalProxies.matcher(originalRemoteAddr).matches();
if (isInternal || (trustedProxies != null &&
trustedProxies.matcher(originalRemoteAddr).matches())) {
#满足条件
}
就是request.getRemoteAddr()要满足这个2个正则之一:internalProxies、trustedProxies
private Pattern internalProxies = Pattern.compile(
"10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" +
"192\\.168\\.\\d{1,3}\\.\\d{1,3}|" +
"169\\.254\\.\\d{1,3}\\.\\d{1,3}|" +
"127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" +
"172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
"172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
"172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
"0:0:0:0:0:0:0:1|::1");
private Pattern trustedProxies = null;
trustedProxies没找到设置的地方,internalProxies是可以配置的
server.tomcat.remoteip.internal-proxies=xxxx
关键问题,为啥request.getRemoteAddr()没有匹配internalProxies;我内网测试一直没问题。
我在出问题的环境,用arthas拿一下request.getRemoteAddr()这个值:watch org.apache.catalina.connector.Request getRemoteAddr "{params,returnObj}" -x 2
结果拿出来,是这台机器的公网ip,不满足上面的正则;参考上面springboot把拿到的ip配置到server.tomcat.remoteip.internal-proxies就好了。
1.确认Nginx配置:proxy_set_header X-Forwarded-Port $server_port;
2.确认SpringBoot配置:server.tomcat.remoteip.protocol-header=X-Forwarded-Port
3.使用的是其他端口,但是取到的是443
现象:
request.getServerPort()得到443
request.getHeader("X-Forwarded-Port")得到:9999,9999
方案1:将Nginx和springboot配置和获取的请求头调整为X-Forwarded-tPort
方案2(推荐):Zuul配置:zuul.add-proxy-headers=false