序言
傳統web瀏覽器應用采用客戶端主動請求方式,只有在收到瀏覽器請求時服務端才返回消息,這種模式已經不能滿足日益多樣化的web應用需求,例如:
在線聊天系統:需要實時獲取聊天消息。
實時監控系統:需要實時獲取監控對象狀態。如儀表讀數、告警信息等。
隨着html技術演進,發展出了多種服務器推送技術,用於服務器向瀏覽器客戶端推送消息。
Ajax輪詢
采用Ajax定時向服務端發送請求檢查有無消息更新。網頁定時向服務器發送請求,若服務器有消息推送,則返回消息,否則返回空消息,如下圖所示:
這種輪詢方式需要發送大量無效請求,大大消耗了服務器資源,且推送消息的實時性較低。
Ajax長輪詢
Ajax長輪詢對前面的Ajax輪詢方式做了改進,服務端收到請求后,不再立即返回,而是等待有消息推送時返回。網頁收到服務端返回的消息后,立即發起一個新的請求,等待下一個推送消息。
采用這種方式的服務端實現比前者復雜,需要維護一個客戶端建立的連接列表,當產生對某個客戶端的推送消息后找到對應的連接並發送。優勢是減少了輪詢消耗,發送事件的實時性得到增強。
Server-Send Event
Server-Send Event是html5標准新增的技術,它延用了Ajax長輪詢的思路,並對其進行了一些規范。Server-Send Event讓服務端可以向客戶端流式發送文本消息,並在發送完一個消息后保持請求不結束,連接始終保持。如下圖所示:
網頁調用EventSource接口向服務器發送請求:
var source = new EventSource('http://localhost:8080');
source.addEventListener('message', function(e) { console.log(e.data); }, false);
服務器返回的Content-Type頭必須為text/event-stream,且返回完一個消息后不關閉請求,后續消息仍然使用同一個請求返回。瀏覽器會自動以換行符識別每個消息。
響應頭
Content-Type: text/event-stream
X-Accel-Buffering: no
響應體
event: userlogin
data: {"username": "John123"}
event: message
data: 123
如果服務端返回的消息通過nginx等代理服務器返回給客戶端時,可能受到nginx緩存機制的影響。某些情況下,nginx會將服務端返回體緩存起來,等待所有返回接受完畢后再統一返回給客戶端,在server-send event情況下將導致客戶端無法及時接收到消息。需要在返回頭中添加X-Accel-Buffering: no,以防止nginx做緩存。
使用華為API gateway提供
Server-Send Event類型的
API服務建立后端服務
登錄華為雲https://console.huaweicloud.com/,創建彈性雲服務器
輸入apt install nodejs安裝nodejs,使用nodejs創建服務器,並輸入下列示例代碼。
var http = require("http");
http.createServer(function (req, res) {
if (req.url === "/stream") {
res.writeHead(200, {
"Content-Type":"text/event-stream",
"X-Accel-Buffering":"no",
});
res.write("data: " + (new Date()) + "\n\n");
interval = setInterval(function () {
res.write("data: " + (new Date()) + "\n\n"); 12 }, 1000);
req.connection.addListener("close", function () {
clearInterval(interval);
}, false);
}
}).listen(8080);
上面代碼是服務器每秒向客戶端發送時間的示例。將上面的代碼保存為server.js,然后執行nodejs server.js &
就啟動了監聽在8080端口的服務器。
添加安全組
將8080端口添加到安全組規則,使得外部可以訪問雲服務器的8080端口。
創建API
API網關提供從內網訪問雲服務器的能力,不需要申請公網彈性IP,就可以通過VPC通道開放API。
登錄華為雲https://console.huaweicloud.com/apig/ ,首先創建VPC通道,端口為8080
將彈性雲服務器添加到VPC通道:
創建API,認證類型選擇APP
“請求Path”填“/stream”,“開啟跨域”選項選擇開啟
創建API完成后,發布API到RELEASE環境。
創建APP並綁定API
在應用管理界面創建一個APP,並綁定剛剛創建的API。
創建OPTIONS方法的API
OPTIONS方法的API是提供給瀏覽器發送跨域請求的預請求使用,同樣選擇開啟跨域(CORS),並將后端配置為Mock。
點完成創建API后,發布API到RELEASE環境。
創建網頁,訪問API
1.要訪問APP認證方式的API,需要通過APP的key和secret生成簽名,才能校驗通過。生成簽名使用下面鏈接下載的javascript SDK
https://console.huaweicloud.com/apig/?agencyId=c65a0db86e514fe298cdc57c6273411a®ion=cn-south-1&locale=zh-cn#/apig/manager/useapi/sdk
2.由於IE瀏覽器不支持Server Sent Event,需要從https://github.com/Yaffle/EventSource/下載瀏覽器兼容的Server Sent Event實現。
搜索並刪除下面四行代碼:
if (url.slice(0, 5) !== "data:" &&
url.slice(0, 5) !== "blob:") {
requestURL = url + (url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId="+ encodeURIComponent(lastEventId);
}
3.創建index.html,內容如下:
<html>
<head>
<title>SSE APP test</title>
</head>
<body>
SSE APP test
<div id="a"></div>
<script src="js/eventsource.js"></script> 09 <script src="js/hmac-sha256.js"></script>
<script src="js/moment.min.js"></script>
<script src="js/moment-timezone-with-data.min.js"></script>
<script src="signer.js"></script>
<script>
var req = new signer.HttpRequest()
req.method = "GET"
req.host = "d3da6a917a844df3bd02896496b1b75b.apigw.cn-south-1.huaweicloud.com"
req.uri = "/stream"
var sig = new signer.Signer();
sig.AppKey = "<your app key>"
sig.AppSecret = "<your app secret>"
var opts = sig.Sign(req);
var source = new EventSourcePolyfill("http://d3da6a917a844df3bd02896496b1b75b.apigw.cn-south-1.huaweicloud.com" + req.uri, {
headers: opts.headers
});
source.onmessage = function (event) {
document.getElementById("a").innerHTML = event.data;
};
</script>
</body>
</html>
將剛剛創建的APP的AppKey和AppSecret填入上面指定位置。在本地用瀏覽器打開此頁面,可以看到頁面上顯示的時間每秒刷新一次。
以上就是對如何實現在線聊天系統中的實時消息獲取的詳解,想要了解更多,點擊這里立即體驗一番吧~