一個完整的WebSocket流程(java實現):html
upstream paas_gateway { least_conn; server ip:port; keepalive 1000; keepalive_timeout 65; } server{ listen 9001; server_name localhost; root /paas-web; index index.html; location /paas-web { .... } location /paas-ws { rewrite ^/paas-ws/(.*)$ /$1 break; proxy_pass http://paas_gateway; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_Forwarded_for; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_max_temp_file_size 0; proxy_connect_timeout 90s; proxy_send_timeout 90s; proxy_read_timeout 90s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; } }
設置WebSocket路由請求,當前端請求/paas-ws走以上配置。前端
spring: cloud: gateway: routes: #具體的路由信息,是一個數組,每個路由基本包含部分: - id: bbb(模塊名稱) uri: lb://bbb predicates: - Path=/bbbapi/** - id: bbb-ws uri: lb:ws://bbb predicates: - Path=/bbbwsapi/**
1.SpringBoot啓動設置(WSServer爲websocket請求類):java
@SpringBootApplication public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(RunApplication.class); ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args); //解決WebSocket不能注入的問題 WSServer.setApplicationContext(configurableApplicationContext); }
2.WebSocket實現:nginx
@ServerEndpoint(value = "server/{userId}") @Component @Slf4j public class WSServer { //此處是解決沒法注入的關鍵 private static ApplicationContext applicationContext; //要注入的service或者dao private WSService wsService; public static void setApplicationContext(ApplicationContext applicationContext) { WSServer.applicationContext = applicationContext; } /** * 當前服務端的鏈接數 */ private static int onlineCount = 0; /** * 與某個客戶端的鏈接會話,須要經過Session對象來向客戶端發送數據 */ private Session session; /** * 用戶id */ private String userId; /** * 存放每一個客戶端對應的webSocket對象 */ private static Map<Session, String> webSocketMap = new ConcurrentHashMap<>(); /** * 增長鏈接數 */ public static synchronized void addOnlineCount() { onlineCount++; } /** * 減小鏈接數 */ public static synchronized void subOnlineCount() { onlineCount--; } /** * 鏈接成功時調用的方法 * * @param session 與某個客戶端的鏈接回話,經過這個參數給客戶端發送數據 * @param userId 用戶id */ @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { // 鏈接數增長 addOnlineCount(); this.session = session; this.userId = userId; // 保存鏈接關聯信息 webSocketMap.put(session, userId); log.error("有新鏈接加入!當前在線人數爲" + getOnlineCount()); log.error("當前用戶開始[{}]", webSocketMap); this.onConnectQueryAndSend(userId); } @OnClose public void onClose(Session session) { webSocketMap.remove(session); subOnlineCount(); log.error("有一鏈接關閉!當前在線人數爲" + getOnlineCount()); log.error("當前用戶關閉[{}]", webSocketMap); } public static synchronized int getOnlineCount() { return onlineCount; } /** * 設置先後端通訊 */ @OnMessage public void onMessage(String message, Session session) { try { if (webSocketMap.containsKey(userId)) { if (message.equals("ping")) { session.getBasicRemote().sendText("pong"); } } } catch (IOException e) { e.printStackTrace(); } } @OnError public void onError(Session session, Throwable throwable) { subOnlineCount(); webSocketMap.remove(userId); if (throwable.getClass().equals(EOFException.class)) { log.info("用戶:{}的鏈接因nginx鏈接超時重連,等待客戶端重連", userId); } else { // TODO: 2018/11/26 統一異常信息 throwable.printStackTrace(); } } public void onConnectQueryAndSend(String userId) { // 查詢用戶當前全部的消息 .... } }
前端請求:localhost:9001/paas-ws/bbbwsapi/server/1web
最後:
前端WebSocket實現,筆者不會,這裏沒有列出。spring