建立 WebSocket 應用程式
使用 Ktor 在 Kotlin 中建立 WebSocket 應用程式
程式碼範例: tutorial-server-websockets
使用的外掛程式:
本文將引導你完成使用 Ktor 在 Kotlin 中建立 WebSocket 應用程式的過程。它建立在
本文將教你如何執行以下操作:
- 建立使用 JSON 序列化的服務。
- 透過 WebSocket 連線傳送與接收內容。
- 同時向多個用戶端廣播內容。
先決條件
你可以獨立完成此教學,但我們建議你先完成
我們建議你安裝 IntelliJ IDEA,但你也可以使用其他偏好的 IDE。
Hello WebSockets
在本教學中,你將基於
Task 物件的功能。為了實現這一點,你需要加入 使用外掛程式建立初始專案
導覽至 Ktor 專案產生器。
在 Project artifact 欄位中,輸入 com.example.ktor-websockets-task-app 作為專案構件的名稱。

在外掛程式區段搜尋並點擊 Add 按鈕來加入以下外掛程式:
- Content Negotiation
- kotlinx.serialization
- WebSockets
- Static Content

加入外掛程式後,它們將顯示在外掛程式區段的右上角。
你將看到所有即將加入專案的外掛程式清單:

點擊 Download 按鈕來產生並下載你的 Ktor 專案。
加入起始程式碼
下載完成後,在 IntelliJ IDEA 中開啟專案並遵循以下步驟:
- 導覽至 src/main/kotlin 並建立一個名為 model 的新子套件。
在 model 套件內建立一個新的 Task.kt 檔案。
開啟 Task.kt 檔案並加入一個
enum來表示優先級,以及一個data class來表示任務:kotlin請注意,
Task類別標記了來自kotlinx.serialization程式庫的Serializable註解。這意味著執行個體可以與 JSON 互相轉換,從而允許其內容在網路上傳輸。因為你包含了 WebSockets 外掛程式,產生器已在 src/main/kotlin 內的 Webwebsockets.kt 檔案中加入了一個
webSocket路由,並在 Routing.kt 檔案中加入了相關設定。- 開啟 Webwebsockets.kt 檔案,並將現有的
.configureWebsockets()函式替換為以下內容:kotlin- 安裝 WebSockets 外掛程式並使用標準設定進行配置。
- 設定
contentConverter屬性,使外掛程式能夠透過kotlinx.serialization程式庫序列化傳送與接收的物件。
開啟 Routing.kt 檔案,並將現有的
Application.configureRouting()函式替換為下方的實作:kotlin- 路由配置了單一端點,相對 URL 為
/tasks。 - 收到請求後,任務清單會透過 WebSocket 連線序列化傳送。
- 所有項目傳送完畢後,伺服器會關閉連線。
為了示範目的,在傳送任務之間引入了一秒鐘的延遲。這讓你可以觀察到任務在用戶端中逐一出現。若沒有這個延遲,此範例看起來會與先前文章中開發的
RESTful 服務以及了解如何使用 Kotlin 和 Ktor 建置後端服務,其中包含一個產生 JSON 檔案的 RESTful API 範例。Web 應用程式完全相同。了解如何使用 Kotlin、Ktor 和 Thymeleaf 範本建置網站。此階段的最後一步是為此端點建立一個用戶端。因為你包含了
靜態內容外掛程式,Ktor 專案產生器已在 src/main/resources/static 內加入了一個 index.html 檔案。了解如何提供靜態內容,例如樣式表、指令碼、圖片等。- 路由配置了單一端點,相對 URL 為
開啟 index.html 檔案,並將現有內容替換為以下內容:
html此頁面使用了所有現代瀏覽器都提供的
WebSocket類型。你在 JavaScript 中建立此物件,並將端點的 URL 傳遞給建構函式。隨後,你為onopen、onclose和onmessage事件附加事件處理常式。觸發onmessage事件時,你會使用文件物件的方法向表格附加一行。在 IntelliJ IDEA 中,點擊執行按鈕 (
) 來啟動應用程式。
導覽至 http://0.0.0.0:8080/static/index.html。你應該會看到一個包含按鈕的表單和一個空表格:

點擊表單後,任務會從伺服器載入,並以每秒一個的速度出現。因此,表格會逐次填入內容。你也可以透過開啟瀏覽器 開發者工具 中的 JavaScript 控制台 來查看記錄訊息。

至此,該服務運作符合預期。WebSocket 連線已開啟,項目被傳送至用戶端,隨後連線關閉。底層網路存在許多複雜性,但 Ktor 預設處理了所有這些細節。
理解 WebSockets
在進入下一個階段之前,回顧 WebSockets 的一些基本概念可能會有所幫助。如果你已經熟悉 WebSockets,可以直接繼續 改進你的服務設計。
在先前的教學中,你的用戶端傳送 HTTP 請求並接收 HTTP 回應。這種模式運作良好,並使網際網路具備擴展性與韌性。
然而,它不適用於以下情境:
- 內容是隨著時間推移增量產生的。
- 內容隨事件頻繁變更。
- 用戶端需要在產生內容時與伺服器互動。
- 一個用戶端傳送的資料需要迅速傳播給其他用戶端。
這些情境的範例包括股票交易、購買電影和音樂會門票、線上拍賣競標,以及社群媒體中的聊天功能。WebSockets 的開發就是為了處理這些情況。
WebSocket 連線建立在 TCP 之上,且可以持續較長時間。該連線提供 全雙工通訊,這意味著用戶端可以同時向伺服器傳送訊息並從中接收訊息。
WebSocket API 定義了四種事件(open、message、close 和 error)以及兩種操作(send 和 close)。如何存取這些功能可能因不同的語言和程式庫而異。例如,在 Kotlin 中,你可以將傳入訊息序列視為 Flow 來處理。
改進設計
接下來,你將重構現有程式碼,為更進階的範例騰出空間。
在 model 套件中,建立一個新的 TaskRepository.kt 檔案。
開啟 TaskRepository.kt 並加入
TaskRepository類型:kotlin你可能還記得先前教學中的這段程式碼。
- 導覽至 src/main/kotlin 並開啟 Routing.kt 檔案。
你現在可以透過利用
TaskRepository來簡化Application.configureRouting()中的路由:kotlin
透過 WebSockets 傳送訊息
為了說明 WebSockets 的強大功能,你將建立一個新的端點,其中:
- 當用戶端啟動時,它會接收所有現有任務。
- 用戶端可以建立並傳送任務。
- 當一個用戶端傳送任務時,其他用戶端會收到通知。
在 Routing.kt 檔案中,將目前的
.configureRouting()方法替換為下方的實作:kotlin透過這段程式碼,你完成了以下操作:
- 將傳送所有現有任務的功能重構為一個輔助方法。
- 在
routing {}區塊中,建立了一個執行緒安全的session物件清單,用以追蹤所有用戶端。 - 加入了一個相對 URL 為
/tasks2的新端點。當用戶端連接到此端點時,對應的session物件會被加入清單。伺服器隨後進入無限迴圈,等待接收新任務。收到新任務後,伺服器將其存儲在存儲庫中,並向所有用戶端(包括當前用戶端)發送複本。
為了測試此功能,你將建立一個新頁面,擴充 index.html 中的功能。
在 src/main/resources/static 中建立一個名為 wsClient.html 的新 HTML 檔案。
開啟 wsClient.html 並加入以下內容:
html這個新頁面引入了一個 HTML 表單,使用者可以在其中輸入新任務的資訊。提交表單後,會呼叫
sendTaskToServer()事件處理常式。這會使用表單資料建立一個 JavaScript 物件,並使用 WebSocket 物件的.send()方法將其傳送至伺服器。在 IntelliJ IDEA 中,點擊重新執行按鈕 (
) 來重新啟動應用程式。
要測試此功能,請並排開啟兩個瀏覽器並遵循以下步驟。
- 在瀏覽器 A 中,導覽至 http://0.0.0.0:8080/static/wsClient.html。你應該會看到顯示預設任務。
- 在瀏覽器 A 中加入一個新任務。新任務應該會出現在該頁面的表格中。
- 在瀏覽器 B 中,導覽至 http://0.0.0.0:8080/static/wsClient.html。你應該會看到預設任務,以及你在瀏覽器 A 中加入的任何新任務。
- 在任一瀏覽器中加入任務。你應該會看到新項目同時出現在兩個頁面上。

加入自動化測試
為了簡化你的品質保證 (QA) 流程並使其快速、可重現且自動化,你可以使用 Ktor 內建的
將以下相依性加入 build.gradle.kts,以便你在 Ktor Client 中配置對
內容交涉的支援:Content Negotiation 外掛程式有兩個主要目的:交涉用戶端與伺服器之間的媒體類型,以及將內容以特定格式進行序列化/反序列化。kotlin在 IntelliJ IDEA 中,點擊編輯器右側的 Gradle 通知圖示 (
) 來載入 Gradle 變更。
導覽至 src/test/kotlin 並開啟 ServerTest.kt 檔案。
將產生的測試類別替換為下方的實作:
kotlin透過此設定,你:
- 配置你的服務在測試環境中執行,並啟用與生產環境相同的功能,包括 JSON 序列化與 WebSockets。
- 在 Ktor Client中配置內容交涉與 WebSocket 支援。若沒有這些,用戶端在使用 WebSocket 連線時將不知道如何進行物件的 JSON (反)序列化。了解如何建立與配置 Ktor 用戶端。
- 宣告你期望服務回傳的
Tasks清單。 - 使用
client物件的.webSocket函式向/tasks傳送請求。 - 將傳入的任務作為
Flow處理,並將其逐一加入清單。 - 在接收到所有任務後,以通常的方式比較
expectedTasks與actualTasks。
後續步驟
做得好!透過結合 WebSocket 通訊與 Ktor Client 的自動化測試,你已顯著增強了工作管理器服務。
繼續閱讀
