一个完整的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