十年前,若需開發實時應用(如聊天或更新feed),首選方案是輪詢(polling)。此技術通過定時、重複發送HTTP請求到服務器獲取更新數據。然而,即使沒有新信息,請求仍會發送,造成帶寬和服務器處理能力浪費。
所幸,時代變遷。如今使用JavaScript,我們可以藉助EventSource庫建立SSE(服務器發送事件)連接。本文將探討SSE概念,並提供簡要教程。
不同於傳統HTTP請求(客戶端發出請求,服務器返迴響應),SSE連接始終保持打開狀態,實現服務器到客戶端的單向通信。與允許雙向通信的WebSocket不同,SSE僅服務器向客戶端發送數據,客戶端在連接期間實時接收。
連接建立後,數據以事件形式到達JavaScript客戶端,無需像輪詢那樣不斷向服務器請求更新。服務器負責在必要時發送包含更新數據的事件。
除非連接關閉,客戶端將持續等待服務器發送的新數據事件,這使其成為構建需要持續更新的通知、儀錶盤或聊天的理想技術。
為了實踐上述概念,我們將創建一個Node.js(後端)應用,提供SSE連接端點,供JavaScript客戶端(前端)使用。
應用是一個系統,用戶需輸入UserID並建立SSE連接。之後,服務器每5秒發送一次事件,返回已連接用戶列表。如果用戶關閉連接,則會自動從已連接用戶列表中移除。
讓我們開始!
<code class="language-bash">npm init -y npm i express</code>
創建index.js文件,集中後端邏輯。此外,創建一個/public文件夾,存放index.html和script.js文件來管理頁面。結構如下:
<code>/public index.html script.js index.js package.json</code>
在index.js中,導入express庫(用於創建HTTP端點):
<code class="language-javascript">import express from "express" import fs from "fs" import path from "path" const app = express() app.use(express.json()) app.use(express.static(path.join(path.resolve(path.dirname("")), "public"))) app.get("/", (_, res) => { res.writeHead(200, { "content-language": "text/html" }) const streamIndexHtml = fs.createReadStream("index.html") streamIndexHtml.pipe(res) }) const PORT = 3000 app.listen(PORT, () => console.log(`Server is running on ${PORT} port`))</code>
在/public/index.html中,創建一個基本的HTML,顯示標題並測試服務器是否運行:
<code class="language-html"><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Server Sent Events Demo</title> <h1>Server Sent Events Demo (SSE)</h1> </head> <body> </body> </html></code>
現在,在終端運行npm start,頁面應該會在瀏覽器中顯示:
回到後端,創建connection.js文件,管理用戶與服務器的連接:
<code>/public index.html script.js index.js connection.js package.json</code>
在其中,導出Connection類,存儲已連接用戶映射,以及registerUser方法(註冊新用戶)和removeUser方法(從映射中移除用戶):
<code class="language-bash">npm init -y npm i express</code>
由於Connection類隔離了連接管理邏輯,我們需要在服務器(index.js)中配置一個端點,以便客戶端可以啟動SSE通信,這些連接將由Connection類管理:
<code>/public index.html script.js index.js package.json</code>
這裡有三個重點:
Content-Type: text/event-stream
頭響應客戶端。這允許客戶端識別SSE通信並創建EventSource對像以建立連接。 req.on("close", () => {})
事件監控關閉的連接,允許將斷開連接的用戶從連接映射中移除。 後端已完成!現在可以關注前端了。
由於服務器已提供SSE連接端點,客戶端需要請求此地址並等待接收發送的事件。
在index.html文件中,我們將創建:
<ul><ul>
標籤,顯示已連接用戶列表,該列表將使用服務器發送的事件更新。 <code class="language-javascript">import express from "express" import fs from "fs" import path from "path" const app = express() app.use(express.json()) app.use(express.static(path.join(path.resolve(path.dirname("")), "public"))) app.get("/", (_, res) => { res.writeHead(200, { "content-language": "text/html" }) const streamIndexHtml = fs.createReadStream("index.html") streamIndexHtml.pipe(res) }) const PORT = 3000 app.listen(PORT, () => console.log(`Server is running on ${PORT} port`))</code>
然後在script.js中添加JS代碼:
<code class="language-html"><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Server Sent Events Demo</title> <h1>Server Sent Events Demo (SSE)</h1> </head> <body> </body> </html></code>
在瀏覽器中打開兩個標籤頁測試實時連接,觀察已連接用戶的更新。
這樣就完成了一個簡單的SSE實時連接系統。此技術非常適合服務器需要持續向客戶端發送單向數據的場景,例如feed、聊天或儀錶盤。
請注意,為了完整性,我補充了錯誤處理和一些代碼細節,例如在closeConnection
函數中添加了eventSource
的檢查以及在startConnection
函數中添加了onerror
事件處理程序。 這些改進增強了代碼的健壯性和可靠性。
以上是使用SSE(服務器式事件)創建實時應用程序的詳細內容。更多資訊請關注PHP中文網其他相關文章!