被要求一个这样的需求:要求项目和websocket使用一个端口。经过一周激烈争论,领导终于同意可以可以开通一个端口,一个月了,端口还没有开。
正式环境已经通过此方法进行部署,没有问题。
前言
因涉及到内外网安全问题,被要求使用nginx进行代理,不能直连。即对websocket做一个反向代理即可。
项目信息:springboot(cloud等),yeauty集成的websocket(推荐使用,实现非常方便),nginx,websocket在线测试网站(百度搜有很多)
项目搭建
引入依赖
1 <dependencies> 2 <dependency> 3 <groupId>org.yeauty</groupId> 4 <artifactId>netty-websocket-spring-boot-starter</artifactId> 5 <version>0.7.5</version> 6 </dependency> 7 </dependencies>
添加代码
有两个文件,可以直接复制到项目中,如图:
Websocket.java:
1 package com.example.springboottest.common.websocket; 2 3 4 import org.springframework.stereotype.Component; 5 import org.yeauty.annotation.*; 6 import org.yeauty.pojo.Session; 7 8 import java.util.ArrayList; 9 import java.util.List; 10 11 @Component 12 @ServerEndpoint(port = 9906,path = "/WebSocket") 13 public class WebSocket { 14 15 /** 16 * 存放所有在线的客户端 17 */ 18 19 20 private static List<Session> clients = new ArrayList<>(); 21 22 @OnOpen 23 public void onOpen(Session session) { 24 System.out.println("open"); 25 System.out.println("remoteAddress" + session.remoteAddress()); 26 //将新用户存入在线的组 27 clients.add(session); 28 sendMessage("hello Word!"); 29 } 30 31 /** 32 * 客户端关闭 33 * 34 * @param session session 35 */ 36 37 38 @OnClose 39 public void onClose(Session session) { 40 System.out.println(session.remoteAddress() + ":closeWebSocket"); 41 } 42 43 /** 44 * 发生错误 45 * 46 * @param throwable e 47 */ 48 49 50 @OnError 51 public void onError(Throwable throwable) { 52 System.out.println("websocket:error"); 53 throwable.printStackTrace(); 54 } 55 56 /** 57 * 收到客户端发来消息 58 * 59 * @param message 消息对象 60 */ 61 62 @OnMessage 63 public void onMessage(String message, Session session) { 64 System.out.println(message); 65 sendMessage("hello Word!"); 66 } 67 68 public void sendMessage(String message) { 69 try { 70 if (clients.size() > 0) { 71 for (Session session : clients) { 72 session.sendText(message); 73 } 74 } 75 76 } catch (Exception e) { 77 e.printStackTrace(); 78 } 79 80 } 81 }
WebSocketConfig.java:
1 package com.example.springboottest.common.websocket; 2 3 import org.springframework.context.annotation.Bean; 4 5 import org.springframework.context.annotation.Configuration; 6 import org.yeauty.standard.ServerEndpointExporter; 7 8 9 @Configuration 10 public class WebSocketConfig { 11 @Bean 12 public ServerEndpointExporter serverEndpointExporter() { 13 return new ServerEndpointExporter(); 14 } 15 }
启动项目测试websocket
nginx代理
NGINX从1.3版本开始支持WebSocket,其可以作为一个反向代理和为WebSocket程序做负载均衡。此博客不涉及内部原理等,放个干货。
反向代理
先把我自己的nginx配置发出来:
1 #user nobody; 2 worker_processes 1; 3 4 #error_log logs/error.log; 5 #error_log logs/error.log notice; 6 #error_log logs/error.log info; 7 8 #pid logs/nginx.pid; 9 10 11 events { 12 worker_connections 1024; 13 } 14 15 16 http { 17 map $http_upgrade $connection_upgrade { 18 default upgrade; 19 '' close; 20 } 21 22 upstream websocket { 23 #ip_hash; 24 hash $remote_addr consistent; 25 server localhost:9907; 26 } 27 28 # 以下配置是在server上下文中添加,location指用于websocket连接的path。 29 30 server { 31 listen 9908; 32 server_name localhost; 33 #access_log /var/log/nginx/yourdomain.log; 34 35 location /WebSocket { 36 root html; 37 index index.html index.htm; 38 proxy_pass http://websocket/WebSocket; 39 proxy_connect_timeout 4s; #配置点1 40 proxy_read_timeout 60s; #配置点2,如果没效,可以考虑这个时间配置长一点 41 proxy_send_timeout 12s; #配置点3 42 43 proxy_set_header Host $host; 44 proxy_set_header X-Real-IP $remote_addr; 45 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 46 47 proxy_http_version 1.1; 48 proxy_set_header Upgrade $http_upgrade; 49 proxy_set_header Connection "upgrade"; 50 } 51 } 52 }
代理端口为9908,坚挺的地址就是/WebSocket,下面测试一下:
至此反向代理已经完成。
负载均衡
如果想做负载均衡,可以在upstream websocket {}中加一个server就可以了,比如复制一下项目,将websocket端口改为9907
@ServerEndpoint(port = 9907,path = "/WebSocket")
连上之后发送信息为hello world!2
sendMessage("hello Word!2");
然后连上反向代理的链接,连接之后发现连的是9906的链接,如图:
此时我把9906断掉,再次连接时:
此时遇到问题,当负载均衡时,9906断了之后,没有自动转为9907的链接。在客户端监听此链接,如果查实连接不上则进行重新链接,即可使用9907的服务。