记一次springboot项目websocket 从nginx转发到springgateway转发具体服务中产生的问题
1.错误日志
错误日志如下:
nested exception is java.lang.IllegalArgumentException: wsHandshakeRequest.unknownScheme] with root cause
java.lang.IllegalArgumentException: wsHandshakeRequest.unknownScheme
atorg.apache.tomcat.websocket.server.WsHandshakeRequest.buildRequestUri(WsHandshakeRequest.java:164) ~[tomcat-embed-websocket-9.0.38.jar!/:9.0.38]
2.问题解决:
1. 首先在代码中打印你的Scheme
HttpServletRequest request2 = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String scheme = request2.getScheme();
如果是打印出来可能是 http,http 或者 http,http, 如果是这样的话直接去看nginx上的日志是否含有
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-proto $scheme;
如果有的话去掉就可以了,在打印Scheme就会是正常的 http 。其实去掉X-Forwarded-proto这个配置就可以 这个是在nginx上解决的。如果在网关解决需要对forwarded做一些处理,暂时没有好的办法。
2.如果不行升级org.apache.tomcat.embed版本到9.0.38
以下是版本对比
3.问题排查思路:
其中走了不少的错路,就按照最后也是最顺利的方式来吧。
1.错误提示scheme是非法字符,那么打印出scheme是 http,http
2.根据错误日志进源码tomcat-embed-websocket查看WsHandshakeRequest逻辑:
明显是因为scheme不符合规范导致的错误提示。
3.根据打印请求头里里面的具体参数发现wsHandshakeRequest.的Scheme是根据
x-forwarded-proto 来的
4.排查项目中配置发现nginx在转发中添加了
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-proto $scheme;
这就导致在请求头中的Forwarded相关值增添了,去掉这两个配置就成功了,websocket连接成功。
5.其中也查阅了tomcat的版本,发现9.0.38以后对协议判断做了优化
4.相关资料讲解
X-Forwarded-Proto
(XFP) ,用来确定客户端与代理服务器或者负载均衡服务器之间的连接所采用的传输协议(HTTP 或 HTTPS)。在服务器的访问日志中记录的是负载均衡服务器与服务器之间的连接所使用的传输协议,而非客户端与负载均衡服务器之间所使用的协议。为了确定客户端与负载均衡服务器之间所使用的协议, X-Forwarded-Proto 就派上了用场。 记录协议。
X-Forwarded-For
(XFF) 在客户端访问服务器的过程中如果需要经过HTTP代理或者负载均衡服务器 。简单来说记录服务经过的ip地址。
对Forwarded的解释