大話 WebSocket 與"尬聊"的實現
一、聊聊 WebSocket
從HTML5技術流行至今,WebSocket已經有非常廣泛的應用:
-
線上遊戲,提供實時的操作互動體驗
-
社交平臺,與好友實時的私信對話
-
新聞動態,獲得感興趣的主題資訊推送
...
這些場景,都需要 伺服器能主動實時的給瀏覽器或客戶端推送訊息 ,注意關鍵詞是 主動,還有實時 !而在HTML5一統江湖之前,由於HTTP在推送場景下的 "薄弱" ,我們需要藉助一些複雜或者非標準的手段來實現。
這些方式包括有:
-
第一種方式是 Ajax輪詢,比如每隔5秒鐘,由瀏覽器對伺服器主動請求資料後返回。
在這種方案下,瀏覽器需要不斷的向伺服器發出請求,問題是比較明顯的,包括:
HTTP 請求頭部會浪費一些頻寬
頻繁重建連線會造成很大的開銷...
-
第二種是 Comet,這個詞好像翻譯為"彗星"?這個是採用 streaming 或 long-pulling 的長連線技術: 伺服器在收到請求時先掛起,等待有事件發生時才返回資料。
Comet 效率提升了不少,它解決了Ajax輪詢的部分問題,利用 HTTP 長連線的特性儘可能的避免了連線、頻寬資源的浪費等等,於是在 很長一段時間 Comet 成為了Web推送技術的主流。
But ,.. Comet 的實現技術比較複雜,不同框架下的實現方式差異很大,在靈活性、效能上也有些欠缺。
關於服務端Comet的技術可以參考下面這篇經典文章: https://www.ibm.com/developerworks/cn/web/wa-lo-comet/
-
第三種就是 Flash,通過Flash 外掛程式碼實現Socket通訊,本質上是基於TCP的通訊模式,由於Flash 需要安裝外掛以及瀏覽器的相容性問題,目前已經逐漸廢棄。
Websocket 出場
WebSocket 出現的目的沒有別的,就是 幹掉前面的東西,Both!
最開始 WebSocket 協議由 RFC6455 定義,其 API 標準包含於 HTML5 範疇之中。
目前各大主流瀏覽器已經能完全支援該技術。然後可以看看下面這個圖:
如上圖,WebSocket 協議中, 瀏覽器和伺服器只需要完成一次握手,兩者之間就直接可以建立永續性的連線,並進行雙向資料傳輸。那麼相比以往的方式,這種方案更加節省資源了,它的實時性、靈活性都要強大不少。
當然,有HTML5標準給它站臺,後臺槓槓的~
那麼一個 WebSocket 的請求響應長成怎麼樣呢?
看下面這個圖:
二、Stomp 是個什麼鬼
一開始我一直認為 Stomp是暴風雨(誤看為 Storm),然後覺得說這個技術挺犀利的。然後在看了 Stomp 的協議介紹後發現,它是如此的簡單.. Stomp 的 全稱叫 Simple Text Orientated Messaging Protocol ,就是一個簡單的文字定向訊息協議,除了設計為簡單易用之外,它的支持者也非常多。
就比如目前主流的訊息佇列伺服器如RabbitMQ、ActiveMQ 都支援 Stomp 協議。
開源地址: http://stomp.github.io/
Stomp 定義了一些簡單的指令,如下:
命令 | 說明 |
---|---|
CONNECT | 建立連線 |
SEND | 傳送訊息 |
SUBSCRIBE | 訂閱主題 |
UNSUBSCRIBE | 取消訂閱 |
BEGIN | 開啟事務 |
COMMIT | 提交事務 |
ABORT | 回滾事務 |
ACK | 確認消費 |
NACK | 訊息丟棄 |
DISCONNECT | 斷開連線 |
一個簡單的STOMP訊息大致如下:
好的,你現在應該瞭解 Stomp是個什麼了,那麼為什麼要介紹這個?
WebSocket 為我們提供了Web 雙向通訊的通道,但對於訊息的互動協議還需要我們來自己實現( WebSocket 果然不夠意思... ) 藉助Stomp 協議,可以很方便的實現一種 "訂閱-釋出" 的通用機制,這個就是非常具有競爭力的一個特性了。
三、SpringBoot 整合 WebSocket
在介紹完WebSocket 之後,接下來幹什麼呢?
可能你看完前面的東西會覺得 WebSocket 是如此之強大,以至於很多場景都應該使用這個技術來實現。那麼如何做?在此前我所介紹的 SpringBoot 也是如此之強大,那麼能不能通過SpringBoot 輕鬆整合WebSocket 呢?
這當然可以!
思索了很久,我決定做一個最簡單的應用展示: 尬聊!
為什麼是"尬聊”,而不是聊天室...
那麼,下面開始講這個案例,在該樣例中會包含一個Controller類、一個HTML頁面以及一個JS指令碼。步驟如下:
A. 引入依賴
新增 spring-boot-starter-websocket 會自動引入 spring-websocket 的依賴,而後者就實現了WebSocket 操作的高階封裝。
還有一個好訊息,就是spring-websocket 也預設支援了 Stomp協議( 看吧,Stomp支持者太多了 )。而除此之外,還內建了一個叫 SocketJS 的東西。
SocketJS 是一個流行的JS庫,主要是在WebSocket之上封裝了一層API,用於支援瀏覽器不相容WebSocket的情況。
其專案地址:https://github.com/sockjs/sockjs-client
其他元件的說明
-
webjars 主要是將一些前端的框架打包到Jar包中以方便我們使用,這裡我們添加了socketJS、stompWebSocket相關的一些包;
-
jackson 用於支援WebSocket訊息的編解碼,是必須新增的。
B. WebSocket 配置
參考下面的程式碼,新增一個JavaConfig風格的配置類:
WebSocketConfig.java
在WebSocketConfig的配置中,有兩點需要關注:
-
registerStompEndpoints 用於新增端點,即瀏覽器通過 ws://xxx 能訪問到的路徑
-
configureMessageBroker 用於做訊息路由配置,包括訂閱主題、方法對映路徑
C. 控制器
控制層除了支援頁面的渲染,還需要對WebSocket訊息進行處理,實現如下:
ConsoleController.java
D. 前端實現
先做一個HTML頁面,編輯 templates/console.html
然後是實現 JS 指令碼,編輯 public/static/console.js
這樣,Web控制檯已經制作好了,執行主程式後,開啟地址
http://localhost:8080/console
進行體驗,如下:
好了,這個案例的確很尷尬..
但是我認為,在這上面做一做改造,應該可以實現一個諸如 "美女聊天室" 的功能的,或者,你可以動手試試。
四、參考文件
https://spring.io/guides/gs/messaging-stomp-websocket/ https://blog.coding.net/blog/spring-static-resource-process https://zh.wikipedia.org/wiki/WebSocket https://halfrost.com/websocket/
歡迎繼續關注"美碼師的補習系列-springboot篇" ,期待更多精彩內容^-^