nginx实现对websocket加密协议wss协议的反向代理以及websocket整合springboot入门(踩坑)

1,000 阅读3分钟

出发点

最近公司需要有一个推送前端消息的需求 首选websocket进行推送,也做过客服系统接触过,最近看了一点websocket的相关内容记录总结一下。

什么是websocket

websocket简单来说就是一个服务端可以向客户端发送请求的一个协议,因为现在企业级开发大部分还是由客户端向服务器发送请求索要请求数据,但是在聊天,消息推送等场景下,需要服务器向web前端或者IOS,Android,小程序推送一些消息,就需要借助websocket工具了

整合springboot

由于博主是需要服务端向web前端发送消息,故需首先整合websocket到后端项目。 Java项目,springboot框架下,首先整合websocket导入自动配置类。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

然后交给spring容器处理

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

==springboot的拦截器无法对ws请求进行拦截。==

进行nginx反向代理转发wss请求

公司项目走的是HTTPS协议,故前端转发的是https请求到nginx代理服务器,ws协议只能直接访问后端websocket接口调用,但是不能满足前端建立websocket请求,故需要使用wss协议进行调用,wss默认端口与https一致为443端口,故可以与https使用同一套加密证书以及端口,这对后面整合wss协议提供了便利。

具体nginx配置

下面就是通过nginx反向代理websocket请求的nginx配置,不做过多赘述 ,具体参考以下两篇文章 wss协议配置解析 wss协议nginx配置

server {
    listen 443 ssl; 
    #监听前端转发的接口
    server_name 0.0.0.0;
    #配置nginx的server_name时,_; 或 0.0.0.0为无效匹配,所有未匹配的域名默认解析到 http的第一个server网站,这点务必注意!
    
    #并且listen配置配置后此配置失效,也就是只通过端口进行请求匹配。
    ssl_certificate /etc/nginx/secret/xxx.crt;#ssl证书
    ssl_certificate_key  /etc/nginx/secret/xxx.pem;#ssl私钥
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;
    charset utf-8;

location = / {
	root    /usr/share/nginx/html;
	index index.html;
}
location ~ /.*\.(gif|jpg|ico|png|js|css|woff|otf|ttf|TTF|svg|json|xlsx|html|htm|mp4|zip|pdf)$ {
	root   /usr/share/nginx/html;
	index index.html;
}
#原来的代理地址
location / {
	proxy_pass http://172.xx.xx.xx:8099/;
}
#!!!!!这里为websocket的代理配置也是踩坑的地方
location /websocket/  {
	proxy_pass http://172.xx.xx.xx:8099;        #通过配置端口指向部署websocker的项目
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
	proxy_set_header X-real-ip $remote_addr;
	proxy_set_header X-Forwarded-For $remote_addr;
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-Proto   $scheme;
}

整合wss协议对于本身是https项目无需过多证书配置,证书通用,端口通用

踩坑

博主踩坑就是location配置时,在网上看到的需要将 proxy_pass 配置为==http://172.28.5.10:8099/;== 这就是坑的所在,由于用的请求路径不同导致此配置一直代理不到。

proxy_pass转发规则

让我们来看 proxy_pass 如何转发,首先看 proxy_pass 的url 配置。 proxy_pass 只是HOST,不包含任何路径,比如 这种情况下,会把匹配到的所有路径直接穿透转发。比如以下的配置

 location /websocket/ {
    proxy_pass http://127.0.0.1:3000;
 }

访问 http://127.0.0.1:80/websocket/cc, 后端结果为 您的 请求 地址是/websocket/cc,此时不会丢弃/websocket/的uri 但是以下情况 proxy_pass 包含路径,这里的路径哪怕只是一个 / 也是存在的 这种情况下,url 里面会去掉 location 匹配的字符串,拼接到 proxy_pass 再进行转发。

 location /websocket/ {
    proxy_pass http://127.0.0.1:3000/;
 }

也就是访问 http://127.0.0.1:81/websocket/cc, 后端结果为 您的 请求 地址是/cc

踩坑解决

也就是==http://172.28.5.10:8099/;== 加上location /websocket/ 的nginx配置 最后代理访问的路径是http://172.28.5.10:8099/{userId};(下面是方法签名路径) @ServerEndpoint("/websocket/{userId}")
public class WebSocket {}

这样就无法转发到对应websocket服务器接口,就一直连接失败 改为==http://172.28.5.10:8099;== ==把后面的/去掉后==,实际访问路径为http://172.28.5.10:8099/websocket/{userId};就可以连接到websocket服务器。

总结

需要知道具体的nginx的location配置的规则,对nginx配置有详细了解,故又去看了一遍nginx的配置详解。 ==问题基本都有解决办法,不要放弃,需要理解每个东西的原理,具体运行流程,基本所有问题都能迎刃而解。==