本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威在線客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。
請訪問:https://kf.shengxunwei.com
對於在線客服與營銷系統,訪客端是指瀏覽網站的互聯網用戶,或是通過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
聯系QQ: 279060597
聯系E-mail:C5118@outlook.com
推薦您關注我的微信訂閱號,在我更新文章或產品信息時會進行推送。