springcloud網關轉發websocket


小編在做微服務項目上遇到一個問題,正如標題描述一樣,但是百度好久未果(太多文章都是互相copy的)

小編決定自己寫一下解決方案。。。

下面只貼部分代碼,如需完整demo請上github獲取

  1. 首先搭建 websocket 的服務端

 

1.1. 在 websocket 服務端的 pom 配置文件中需要有 websocket 的依賴(由於在pom中配置了統一版本管理,這里就不需要寫版本了)

1 <dependency>
2     <groupId>org.springframework.boot</groupId>
3     <artifactId>spring-boot-starter-websocket</artifactId>
4 </dependency>

 

1.2. 略過啟動類,配置 websocket 工具類;配置的說明,在代碼中都有體現

 1 package com.beyond.config;
 2 
 3 
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
 6 import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
 7 import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
 8 
 9 @Configuration
10 // 此注解表示使用STOMP協議來傳輸基於消息代理的消息,此時可以在@Controller類中使用@MessageMapping
11 @EnableWebSocketMessageBroker
12 public class WebSocketAutoConfig implements WebSocketMessageBrokerConfigurer {
13     @Override
14     public void registerStompEndpoints(StompEndpointRegistry registry) {
15         //本實例前端 sockjs 請求路徑為 http://localhost:8888/client/websocket/web/socket
16         registry.addEndpoint("/websocket/web/socket")         //websocket監聽地址,sockjs連接地址(如果有配置項目路徑【server.servlet.context-path】,需要加上)
17                 .setAllowedOrigins("*")         //允許跨域訪問
18                 .withSockJS();                  //使用sockJS
19     }
20 }

 

1.3. 使用 websocket 【使用方式,只寫了 請求回復定時推送 兩種】

 

1.3.1. 請求回復模式【編寫方式和普通的 http 的請求回復很像】

 1 package com.beyond.controller;
 2 
 3 import com.alibaba.fastjson.JSONObject;
 4 import lombok.extern.slf4j.Slf4j;
 5 import org.springframework.messaging.handler.annotation.MessageMapping;
 6 import org.springframework.messaging.handler.annotation.SendTo;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 @RestController
10 @Slf4j
11 public class FirstController {
12 
13     /**
14      * 此方法用於點對點,一發一答
15      *
16      * @param message
17      * @return
18      */
19     @SendTo("/websocket/read/response/message")//前端訂閱消息的地址如果是這個,就會收到該方法的返回結果
20     //MessageMapping 注解可寫在類上,和 RequestMapping 類似
21     @MessageMapping("/websocket1")//前端往這個地址推送數據,類似於 http 的方法請求
22     public String readMessage(String message) {
23         //todo something
24         log.info("message {}", message);
25         return JSONObject.parseObject(message).get("message") + " say: hello word.";
26     }
27 }

 

1.3.2. 定時推送模式【這里需要注入 SimpMessagingTemplate 對象進行操作】;這里引入一點題外知識【注入對象的方式】

 1 package com.beyond.task;
 2 
 3 import lombok.extern.slf4j.Slf4j;
 4 import org.springframework.messaging.simp.SimpMessagingTemplate;
 5 import org.springframework.scheduling.annotation.Async;
 6 import org.springframework.scheduling.annotation.Scheduled;
 7 import org.springframework.stereotype.Component;
 8 
 9 @Component
10 @Async
11 @Slf4j
12 public class WebsocketTask {
13 
14 
15 /*
16  *
17  * 方式一 Autowired 屬性注入 (不推薦使用)
18 //    @Autowired
19 //    private SimpMessagingTemplate simpMessagingTemplate;
20  */
21 
22 /*
23  *
24  * 方式二 set注入,在屬性多的情況下推薦使用
25 //    private SimpMessagingTemplate simpMessagingTemplate;
26 
27 //    @Autowired
28 //    public void setSimpMessagingTemplate(SimpMessagingTemplate simpMessagingTemplate) {
29 //        this.simpMessagingTemplate = simpMessagingTemplate;
30 //    }
31  */
32 
33     /**
34      * 方式三 構造函數注入,在屬性少的情況下推薦使用
35      */
36     private final SimpMessagingTemplate simpMessagingTemplate;
37 
38     public WebsocketTask(SimpMessagingTemplate simpMessagingTemplate) {
39         this.simpMessagingTemplate = simpMessagingTemplate;
40     }
41 
42 
43     /**
44      * 此定時任務用於往 /websocket/send/response/message 訂閱地址定時發送消息;發送消息需要依賴 SimpMessagingTemplate 消息模板
45      */
46     @Scheduled(cron = "*/5 * * * * ?")
47     public void roundSendMessage() {
48         //todo something
49         //向 /websocket/send/response/message 訂閱地址發送消息 [hello word!!]
50         simpMessagingTemplate.convertAndSend("/websocket/send/response/message", "hello word!!");
51     }
52 }

 

  2. 現在就可以用前端代碼測試了,這個代碼是從百度上 copy 后改寫的

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4 <meta charset="UTF-8" />
 5 <title>Spring cloud gateway WebSocket</title>
 6 </head>
 7 <body>
 8     <div>
 9         <div>
10             <button id="connect" onclick="connect()">連接</button>
11             <button id="disconnect"  onclick="disconnect();">斷開連接</button>
12         </div>
13         <div id="conversationDiv">
14             <label>輸入消息</label> <input type="text" id="messgae" />
15             <button id="send" onclick="send();">發送</button>
16             <p id="response"></p>
17         </div>
18     </div>
19     <script src="sockjs.min.js"></script>
20     <script src="stomp.min.js"></script>
21     <script src="jquery.min.js"></script>
22     <script type="text/javascript">
23         var connectioned = false;
24 
25          function connect() {
26                 // websocket的連接地址,此值等於WebSocketMessageBrokerConfigurer中registry.addEndpoint("/websocket/web/socket").withSockJS()配置的地址;如果有項目前綴,需要加上
27                 //var socket = new SockJS('http://192.168.1.95:19999/server/websocket/web/socket');//網關websocket代理地址
28                 var socket = new SockJS('http://192.168.1.95:8888/server/websocket/web/socket');//子項目websocket地址
29                 stompClient = Stomp.over(socket);
30                 stompClient.connect({}, function(frame) {
31                     connectioned = true;
32                     console.log('Connected: ' + frame);
33                     // 客戶端訂閱消息的目的地址:此值等於BroadcastCtl中@SendToUser("/topic/getResponse")注解的里配置的值。這是請求的地址必須使用/user前綴
34                     stompClient.subscribe('/websocket/read/response/message', function(respnose){
35                         console.log("read -------------------");
36                         console.log(respnose.body);
37                     });
38                     
39                      stompClient.subscribe('/websocket/send/response/message', function(respnose){
40                         console.log("------------------- send");
41                         console.log(respnose.body);
42                     });
43                 });
44             }
45 
46 
47             function disconnect() {
48                 if (stompClient != null) {
49                     stompClient.disconnect();
50                 }
51                 connectioned = false;
52                 console.log("Disconnected");
53             }
54 
55             function send() {
56                 if(connectioned){
57                     var name = $('#messgae').val();
58                     console.log("message --- " +name);
59                     //客戶端消息發送的目的:服務端使用BroadcastCtl中@MessageMapping("/websocket1")注解的方法來處理發送過來的消息;如果類上有配置 @MessageMapping 注解,請求路徑需要拼接 [類上/方法上]
60                     stompClient.send("/websocket1", {}, JSON.stringify({ 'message': name }));
61                 }
62             }
63     </script>
64 </body>
65 </html>

 

測試結果就不上圖了,親測可用

 

  3. 網關配置

  先說明下,這里小編踩過坑,在這里要提醒各位同學,在配置 spring cloud gateway 的時候,必須要用 yml 格式的配置文件,否則不生效。但是不知道為什么,有知道的大神可以告訴我!

 

3.1. 網關的pom配置文件中需要引入 springcloud 的 gateway

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

 

3.2. 只需要配置路由轉發規則即可,其他帖子上說要配置其他的,全部都是瞎扯

要使用 yml 格式的配置文件

properties 和 yml 配置文件可以共存【properties 優先級比 yml 高】

#必須使用 yml 格式配置文件,轉發 socket 才會生效
spring:
  cloud:
    gateway:
      #路由轉發
      routes:
        #轉發web請求
        - id: customize-web
          #lb 代表從注冊中心獲取 serverId 來做負載請求
          uri: lb://server
          predicates:
            - Path=/server/websocket/web/socket/info/**
           #如果需要加訪問前綴,轉發是需要去掉;前綴加一層,StripPrefix 值+1
           #filters:
           # - StripPrefix=1
        #轉發websocket
        - id: customize-websocket
          uri: lb:ws://server
          predicates:
            - Path=/server/websocket/web/socket/**

 

到這里就已經配置完成了,在剛剛那個前端實例里面,端口改成 gateway 的端口即可

親測可用

有問題的同學可以留言討論


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM