当前位置:   article > 正文

若依springcloud gateway nacos 集成websocket_nacos websocket

nacos websocket

一.代码部分

相应模块里面添加3个类

WebSocketConfig,MyWebSocketHandler,WebSocketInterceptor

1.WebSocketConfig

  1. package com.ruoyi.config;
  2. import com.ruoyi.handler.MyWebSocketHandler;
  3. import com.ruoyi.interceptor.WebSocketInterceptor;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.beans.factory.annotation.Value;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.web.socket.config.annotation.EnableWebSocket;
  10. import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
  11. import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
  12. /**
  13. * 首先注入一个ServerEndpointExporterBean,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
  14. */
  15. @Configuration
  16. @EnableWebSocket
  17. public class WebSocketConfig implements WebSocketConfigurer {
  18. private static final Logger log = LoggerFactory.getLogger(WebSocketConfig.class);
  19. @Autowired
  20. private MyWebSocketHandler myWebSocketHandler;
  21. @Autowired
  22. private WebSocketInterceptor webSocketInterceptor;
  23. @Value("#{'${websocket.wsHandlers}'.split(',')}")
  24. private String[] paths;
  25. @Override
  26. public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
  27. registry.addHandler(myWebSocketHandler, paths)
  28. .setAllowedOrigins("*")
  29. .addInterceptors(webSocketInterceptor);
  30. }
  31. }

2. MyWebSocketHandler

  1. package com.ruoyi.handler;
  2. import com.ruoyi.common.WebSocketCommon;
  3. import com.ruoyi.common.core.constant.WebSocketConstants;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.socket.*;
  8. import java.io.IOException;
  9. @Component
  10. public class MyWebSocketHandler implements WebSocketHandler {
  11. private static final Logger log = LoggerFactory.getLogger(MyWebSocketHandler.class);
  12. @Override
  13. public void afterConnectionEstablished(WebSocketSession session) {
  14. log.info("connect websocket successful!");
  15. Object userId = session.getAttributes().get(WebSocketConstants.TOKEN);
  16. if(userId==null){
  17. return;
  18. }
  19. WebSocketSession oldSession = WebSocketCommon.CLIENT_SESSION.get(WebSocketCommon.getMapKey(session));
  20. if (oldSession != null) {
  21. log.info("close original session-start");
  22. try {
  23. oldSession.close();
  24. } catch (IOException e) {
  25. log.info("close original session failed");
  26. }
  27. }
  28. //新的会话放入
  29. WebSocketCommon.CLIENT_SESSION.put(WebSocketCommon.getMapKey(session),session);
  30. }
  31. /**
  32. * 接收客户端发送的消息-用作客户端心跳
  33. * @param session
  34. * @param message
  35. */
  36. @Override
  37. public void handleMessage(WebSocketSession session, WebSocketMessage<?> message){
  38. log.info("handle message start");
  39. try {
  40. //String mess = (String) message.getPayload(); //获取客户端发送的消息
  41. //这边可能需要处理更新map里session机制,防止map里面保存的失效,待定,等后面实际运行观察
  42. if(session.isOpen()){
  43. //心跳响应包
  44. session.sendMessage(new PongMessage());
  45. }
  46. } catch (Exception e) {
  47. log.error("e", e);
  48. }
  49. }
  50. @Override
  51. public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
  52. log.info("handle message start");
  53. if (session.isOpen()) {
  54. session.close();
  55. }
  56. log.error("connect error", exception);
  57. Object userid = session.getAttributes().get(WebSocketConstants.TOKEN).toString();
  58. if(userid==null){
  59. return;
  60. }
  61. WebSocketCommon.CLIENT_SESSION.remove(WebSocketCommon.getMapKey(session));
  62. }
  63. @Override
  64. public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus){
  65. log.error("在线人数: {}" + WebSocketCommon.CLIENT_SESSION.size());
  66. log.error("connection closed: " + closeStatus);
  67. WebSocketCommon.CLIENT_SESSION.remove(WebSocketCommon.getMapKey(session));
  68. log.error("在线人数: {}" + WebSocketCommon.CLIENT_SESSION.size());
  69. }
  70. @Override
  71. public boolean supportsPartialMessages() {
  72. return false;
  73. }
  74. }

3.WebSocketInterceptor

  1. package com.ruoyi.interceptor;
  2. import com.ruoyi.common.core.constant.WebSocketConstants;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.http.server.ServerHttpRequest;
  6. import org.springframework.http.server.ServerHttpResponse;
  7. import org.springframework.http.server.ServletServerHttpRequest;
  8. import org.springframework.stereotype.Component;
  9. import org.springframework.web.socket.WebSocketHandler;
  10. import org.springframework.web.socket.server.HandshakeInterceptor;
  11. import java.util.Map;
  12. @Component
  13. public class WebSocketInterceptor implements HandshakeInterceptor {
  14. private static final Logger log = LoggerFactory.getLogger(WebSocketInterceptor.class);
  15. //在握手之前执行该方法, 继续握手返回true, 中断握手返回false. 通过attributes参数设置WebSocketSession的属性
  16. @Override
  17. public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes){
  18. if (request instanceof ServletServerHttpRequest) {
  19. String uri = request.getURI().getPath();
  20. String token = uri.substring(uri.lastIndexOf("/")+1);
  21. attributes.put(WebSocketConstants.TOKEN,token);
  22. log.info("current token is:"+token);
  23. }
  24. return true;
  25. }
  26. @Override
  27. public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
  28. log.info("coming webSocketInterceptor afterHandshake method...");
  29. }
  30. }

二.nacos中关键配置

在ruoyi-gateway-dev.yml 配置文件中添加如下,我是在ruoyi-collection这个模块中使用websocket的,所以配置路由到这个服务

  1. # websocket模块
  2. - id: ruoyi-websocket
  3. uri: lb:ws://ruoyi-collection
  4. predicates:
  5. - Path=/ws/**
  6. - id: ruoyi-websocket
  7. uri: lb:ws://ruoyi-collection
  8. predicates:
  9. - Path=/ws1/**

这边是加了2个ws和ws1路径的配置,然后这样访问ws://ip+port/ws/xxxws://ip+port/ws1/xxx都能连接上,这边注意,配置如下,ruoyi-collection是我新加的模块,这个模块中使用到了,故我在这个模块的配置文件中添加如下配置,{token} 这个表示连接时是动态传的变量

  1. websocket:
  2. wsHandlers: /ws/{token},/ws1/{token}

三.其它说明

1.在ruoyi-gateway-dev.yml中上面的配置中加了下面

filters:

- StripPrefix=1

这个配置,会导致连不上,要注意。

2.如果需要授权才能连接,我是这么实现的,我连接地址后面拼了一个token,例如ws://ip+port/ws/xxx?token=xxxxxx,这样在网关那边鉴权的时候,获取连接后面的token,拿到后正常往后面走,贴出关键代码如下

在gateway模块中

com.ruoyi.gateway.filter.AuthFilter#getToken

  1. private String getToken(ServerHttpRequest request)
  2. {
  3. String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
  4. if(StringUtils.isEmpty(token)){
  5. //尝试从拼接参数中获取token,这步是为了websocket鉴权
  6. Object authorization = request.getQueryParams().get(TokenConstants.AUTHENTICATION);
  7. if(authorization!=null){
  8. token = ((List<?>) authorization).get(0).toString();
  9. }
  10. }
  11. // 如果前端设置了令牌前缀,则裁剪掉前缀
  12. if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
  13. {
  14. token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
  15. }
  16. return token;
  17. }

如果不需要授权的话,则在ruoyi-gateway-dev.yml中配置下白名单即可

  1. # 不校验白名单
  2. ignore:
  3. whites:
  4. - /auth/logout
  5. - /auth/login
  6. - /auth/register
  7. - /*/v2/api-docs
  8. - /csrf
  9. - /collection/sendBoxStatus
  10. - /ws/**
  11. - /ws1/**

3.这边补上上面代码使用到的新加的类,供参考

WebSocketConstants

  1. package com.ruoyi.common.core.constant;
  2. public class WebSocketConstants {
  3. //用户标识
  4. public static String CLIENT_FLAG = "clientId";
  5. //用户标识key
  6. public static String TOKEN = "token";
  7. //每个连接key前缀标识
  8. public static String PREFIX = "prefix";
  9. }
WebSocketCommon
  1. package com.ruoyi.common;
  2. import com.ruoyi.common.core.constant.WebSocketConstants;
  3. import org.springframework.web.socket.WebSocketSession;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. public class WebSocketCommon {
  6. /**
  7. * 保存已登录的会话session
  8. */
  9. public static ConcurrentHashMap<String, WebSocketSession> CLIENT_SESSION = new ConcurrentHashMap();
  10. public static String getMapKey(WebSocketSession session){
  11. Object userId = session.getAttributes().get(WebSocketConstants.TOKEN);
  12. if(userId==null){
  13. return null;
  14. }
  15. String useridStr = userId.toString();
  16. return useridStr;
  17. }
  18. }

最后非常感谢这篇文章的作者,参照这篇文章实现了功能,另外有什么问题欢迎留言,一起探讨。

SpringCloud Gateway 集成 WebSocket服务_哦哈哟小朋友的博客-CSDN博客_gateway整合websocket

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号