.net core 和 WPF 開發升訊威線上客服與營銷系統:使用 WebSocket 實現訪客端通訊

sheng.chao發表於2021-01-15

本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威線上客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。
線上演示環境:https://kf.shengxunwei.com 注意:演示環境僅供演示交流與評估,不保證 7x24 小時可用。

文章目錄列表請點選這裡


對於線上客服與營銷系統,訪客端是指瀏覽網站的網際網路使用者,或是通過APP、微信等內嵌聊天頁面與後臺客服交流的使用者,在本篇文章中,我將詳細介紹如何在 .net core 環境下使用 WebSocket 技術實現訪客在網頁上與伺服器進行通訊。

這裡存在幾個技術難點需要注意:

  • 聊天介面要能無縫嵌入客戶的目標網站,對原網站不能有任何影響。
  • 訪客可以通過網站右下角的浮動框,一邊聊天一邊瀏覽網站,網頁的跳轉、刷星都不能中斷聊天。
  • 需要考慮手機端聊天頁面連線不穩定的情況,要能在APP或瀏覽器切到手機後臺失去連線時,對聊天狀態和資訊進行保持。

訪客端實現的效果:

訪客端在手機上的效果:

後臺客服的實現效果:


在 asp.net core 中配置中介軟體

首先我們要在 Startup.cs 中,啟用 WebSocket 中介軟體:

var webSocketOptions = new WebSocketOptions() 
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

可配置以下設定:

  • KeepAliveInterval - 向客戶端傳送“ping”幀的頻率,以確保代理保持連線處於開啟狀態。 預設值為 2 分鐘。
  • ReceiveBufferSize - 用於接收資料的緩衝區的大小。 高階使用者可能需要對其進行更改,以便根據資料大小調整效能。 預設值為 4 KB。
  • AllowedOrigins - 用於 WebSocket 請求的允許的 Origin 標頭值列表。 預設情況下,允許使用所有源。

接收訪客端的請求

在請求生命週期後期(例如在 Configure 方法或操作方法的後期),檢查它是否是 WebSocket 請求並接受 WebSocket 請求。

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
            {
                await Echo(context, webSocket);
            }
        }
        else
        {
            context.Response.StatusCode = 400;
        }
    }
    else
    {
        await next();
    }

});

在請求期間對 Task 執行 await,如下面的示例所示:

app.Use(async (context, next) =>
{
    using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
    {
        var socketFinishedTcs = new TaskCompletionSource<object>();

        BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

        await socketFinishedTcs.Task;
    }
});

如果從操作方法返回過快,則還可能發生 WebSocket 關閉異常。 接受操作方法中的套接字時,需要用該套接字的程式碼完成執行,然後再從操作方法返回。

收發訪客端訊息

AcceptWebSocketAsync 方法將 TCP 連線升級到 WebSocket 連線,並提供 WebSocket 物件。 使用 WebSocket 物件傳送和接收訊息。
之前顯示的接受 WebSocket 請求的程式碼將 WebSocket 物件傳遞給 Echo 方法。 程式碼接收訊息並立即發回相同的訊息。 迴圈傳送和接收訊息,直到客戶端關閉連線:

private async Task Echo(HttpContext context, WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}

如果在開始迴圈之前接受 WebSocket 連線,中介軟體管道會結束。 關閉套接字後,管道展開。 即接受 WebSocket 時,請求停止在管道中推進。 迴圈結束且套接字關閉時,請求繼續回到管道。

處理訪客端連線斷開

訪客端由於失去連線而斷開連線時,不會自動向伺服器傳送通知。 伺服器只有在客戶端傳送通知時才會收到斷開連線訊息。
如果客戶端並非總是傳送訊息且不希望僅由於連線進入空閒狀態就設定超時,則讓客戶端使用一個計時器並每隔多少秒傳送一條心跳訊息。 在伺服器上,如果某條訊息在上一條訊息發出後的多少秒內尚未到達,則終止連線並報告客戶端已斷開連線。


本文對使用 WebSocket 搭建訪客端通訊框架進行了簡要的介紹,在接下來的文章中,我將具體解構服務端程式的結構和設計、客服端程式的結構和設計,敬請關注。


線上演示環境:https://kf.shengxunwei.com 注意:演示環境僅供演示交流與評估,不保證 7x24 小時可用。

聯絡QQ: 279060597

推薦您關注我的微信訂閱號,在我更新文章或產品資訊時會進行推送。

相關文章