WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議;使用 ws://(非加密)和 wss://(加密)作為協議前綴,該協議不實行同源政策,只要服務器支持,就可以通過它進行跨源通信,本文主要介紹使用 WebSocket 來實作跨域請求,文中所使用到的軟體版本:Chrome 90.0.4430.212、Spring Boot 2.4.4、jdk1.8.0_181,
1、WebSocket 簡介
WebSocket 使得客戶端和服務器之間的資料交換變得更加簡單,允許服務端主動向客戶端推送資料,在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,并進行雙向資料傳輸,在 WebSocket API 中,瀏覽器和服務器只需要做一個握手的動作,然后,瀏覽器和服務器之間就形成了一條快速通道,兩者之間就直接可以資料互相傳送,
目前,很多網站都使用 Ajax 輪詢來實作推送,輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP請求,然后由服務器回傳最新的資料給客戶端的瀏覽器,這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的資料可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源,
HTML5 定義的 WebSocket 協議,能更好的節省服務器資源和帶寬,并且能夠更實時地進行通訊,

瀏覽器通過 WebSocket 物件向服務器發出建立 WebSocket 連接的請求,連接建立以后,客戶端和服務器端就可以通過 TCP 連接直接交換資料,當獲取 WebSocket 連接后,就可以通過 send() 方法來向服務器發送資料,并通過 onmessage 事件來接收服務器回傳的資料,
1.1、WebSocket 語法
let Socket = new WebSocket(url, [protocol]);
1.2、WebSocket 屬性
| 屬性 | 描述 |
| WebSocket.readyState | 只讀屬性 readyState 表示連接狀態,可以是以下值: 0 - 表示連接尚未建立, 1 - 表示連接已建立,可以進行通信, 2 - 表示連接正在進行關閉, 3 - 表示連接已經關倍訓者連接不能打開, |
| WebSocket.bufferedAmount | 只讀屬性 bufferedAmount 表示已被 send() 放入佇列中正在等待傳輸,但是還沒有發出的 UTF-8 文本位元組數, |
1.3、WebSocket 事件
| 事件 | 事件處理程式 | 描述 |
| open | WebSocket.onopen | 連接建立時觸發 |
| message | WebSocket.onmessage | 客戶端接收服務端資料時觸發 |
| error | WebSocket.onerror | 通信發生錯誤時觸發 |
| close | WebSocket.onclose | 連接關閉時觸發 |
1.4、WebSocket 實體
WebSocket 協議本質上是一個基于 TCP 的協議,為了建立 WebSocket 連接,客戶端瀏覽器首先要向服務器發起一個 HTTP 請求,這個請求和通常的 HTTP 請求不同,包含了一些附加頭資訊,其中附加頭資訊"Upgrade: WebSocket"表明這是一個申請協議升級的 HTTP 請求,服務器端決議這些附加的頭資訊然后產生應答資訊回傳給客戶端,客戶端和服務器端的 WebSocket 連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞資訊,并且這個連接會持續存在直到客戶端或者服務器端的某一方主動的關閉連接,
2、WebSocket 實戰
2.1、服務端實作(SpringBoot 版)
2.1.1、引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
2.1.2、注入 ServerEndpointExporter
package com.abc.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
2.1.3、WebSocket 實作類
package com.abc.demo.websocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; @ServerEndpoint(value = "/websocket") @Component public class WebSocketTest { private static Logger logger = LoggerFactory.getLogger(WebSocketTest.class); @OnOpen public void onOpen(Session session) { logger.info("有新連接加入:{}", session.getId()); sendMessage(session); } @OnClose public void onClose(Session session) { logger.info("有一連接關閉:{}", session.getId()); } @OnMessage public void onMessage(String message, Session session) { logger.info("服務端收到客戶端[{}]的訊息:{}", session.getId(), message); } @OnError public void one rror(Session session, Throwable error) { logger.error("發生錯誤"); error.printStackTrace(); } private void sendMessage(Session session) { new Thread(() -> { try { for (int i = 0; i <= 10 && session.isOpen(); i++) { session.getBasicRemote().sendText("服務端訊息" + i); Thread.sleep(1000 * 5); } if (session.isOpen()) { session.getBasicRemote().sendText("服務端訊息發送完畢,"); } session.close(); } catch (Exception e) { e.printStackTrace(); } }).start(); } }
2.2、客戶端實作
websocket.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>websocket測驗</title> <script type="text/javascript"> let websocket = null; function initSocket() { if (window.WebSocket) { websocket = new WebSocket("ws://localhost:8081/websocket"); } else { alert('你的瀏覽器不支持WebSocket'); return; } websocket.onerror = function() { console.log('發生錯誤'); }; websocket.onopen = function(event) { console.log("建立連接"); } websocket.onmessage = function(event) { document.getElementById('message').innerHTML += event.data + '<br/>'; } websocket.onclose = function() { console.log("連接關閉"); } //視窗關閉事件,關閉websocket連接, window.onbeforeunload = function() { websocket.close(); } } initSocket(); function closeWebSocket() { websocket.close(); } function send() { var message = document.getElementById('text').value; websocket.send(message); } </script> </head> <body> <input id="text" type="text" /> <button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button> <div id="message"></div> </body> </html>
2.3、測驗
把 websocket.html 放到 tomcat(埠:8080) 的 webapps\ROOT 下,并啟動 SpringBoot 應用(埠:8081),

參考:https://www.runoob.com/html/html5-websocket.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/308382.html
標籤:HTML5
上一篇:前端之設計稿二三事
下一篇:Bootstrap使用父子表
