最近在瞎搞点东西,用上了Spring Boot 的 WebSocket (SockJS) 服务,但因为只有一台乞丐🐔,而且还挂着 PHP 博客,所以就让某汪帮忙用 Nginx 做反代,将来自某个子域名的请求全都转到 8080 端口的 Tomcat 上,以上为背景。
瞎搞的东西本地开发一直没有问题,但做了反代以后发现 WebSocket 连接不上了,浏览器端连接请求是报 403,而且服务器会有如下错误:
Handshake failed due to invalid Upgrade header: null
以及警告:
o.s.w.s.s.t.h.DefaultSockJsService: Origin check enabled but transport 'jsonp' does not support it.
这个很好解决,搜索一下就会有解决方案 —— 只要添加如下配置就好了(然而还是某汪帮我加的):
在 nginx.conf
的 http
模块添加如下内容
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
在反代的 location 设置中添加如下内容:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
配置完以上内容即可正常访问websocket,经过测试没有发现问题。
再然后,项目准备对外开放之前,想了下是要加 HTTPS 证书的,然后让某汪帮我搞了下看首页没啥问题以为 OK 了,就没做啥测试,结果第二天发现 WebSocket 又特么崩了,访问直接返回403,还以为某汪又改配置了?我看了一下配置文件,没变,还是之前的样子,相关配置也都在,但浏览器访问就是返回 403,同时 SockJS 报下面的异常(后续找的,当时的完整的找不到了,也不想再试一遍了。。。):
in a frame because it set multiple 'x-frame-options' headers with conflicting values ('deny, sameorigin'). falling back to 'deny'.
然后服务端报警告:
o.s.w.s.s.t.h.DefaultSockJsService: Origin check enabled but transport 'jsonp' does not support it.
同时过几秒后 Freemarker 会大量抛出异常(这个可能是我异常处理的锅):
java.lang.IllegalStateException: getOutputStream() has already been called for this response
最后经过测试发现是 HTTPS 的问题。HTTP 就木有问题,联想到反代以后 Tomcat 获取不到用户 IP 的问题,所以我觉得可能是 Tomcat 没有获取到正确的协议的问题,遂让某汪帮我加了X-Forwarded-Proto
头,为了避免后续的未知问题,把X-Forwarded-Port
也加进来了。
Nginx 添加的配置如下:
proxy_set_header X-Forwarded-Port $Server_port;
proxy_set_header X-Forwarded-Proto $scheme;
同时,Spring Boot 配置文件里也要加上如下配置:
server:
use-forward-headers: true
这里多说几句,因为我用的是内嵌的 Tomcat 容器,所以只要在 Spring Boot 的配置文件里加上这个配置就好了,如果是打包成 War 包的形式,可以搜索并参考 Tomcat 在 Nginx 反代的情况下获取用户真实 IP 的做法。
如: Jetty/Tomcat + Nginx反向代理获取客户端真实IP、域名、协议、端口。
另外,这里添加这一句配置是使用默认的 Forward 请求头,如果有需要使用自定义请求头的情况,可以使用如下配置(根据情况自定义即可):
server:
tomcat:
remote-ip-header: X-Forwarded-For
port-header: X-Forwarded-Port
protocol-header: X-Forwarded-Proto
protocol-header-https-value: https
配置完以后,WebSocket 就可以正常使用了😆
最后附上完整的 Nginx Location 配置:
location / {
proxy_set_header Host $Host;
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port $Server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
以上。
请问@(太阳)@(太阳)@(哈哈)
1111
大佬 你忙吗 想向你请教一下我现在遇到的一个 websocket的问题
感谢大佬
我甚至还没做,就想到可能会有问题,来搜你这篇文章了。
大佬 666
有了Spring Boot 做Web爽歪歪,才能有闲工夫打酱油啊