我在業餘時間開發維護了一款免費開源的升訊威在線客服系統,也收穫了許多用戶。對我來說,只要能獲得用戶的認可,就是我最大的動力。
最近客服系統成功經受住了客戶現場組織的壓力測試,獲得了客戶的認可。
客戶組織多名客服上線後,所有員工同一時間打開訪客頁面瘋狂不停的給在線客服發消息,系統穩定無異常無掉線,客服回覆消息正常。消息實時到達無任何延遲。
我會通過一系列的文章詳細分析升訊威在線客服系統的併發高性能技術是如何實現的,使用了哪些方案以及具體的做法。
本篇介紹超強的 SignalR 技術。
什麼是 SignalR?
ASP.NET Core SignalR 是一個開放源代碼庫,可用於簡化嚮應用添加實時 Web 功能。 實時 Web 功能使服務器端代碼能夠將內容推送到客戶端。
適合 SignalR 的候選項:
- 需要從服務器進行高頻率更新的應用。 示例包括遊戲、社交網絡、投票、拍賣、地圖和 GPS 應用。
- 儀表板和監視應用。 示例包括公司儀表板、即時銷售更新或旅行警報。
- 協作應用。 協作應用的示例包括白板應用和團隊會議軟件。
- 需要通知的應用。 社交網絡、電子郵件、聊天、遊戲、旅行警報和很多其他應用都需使用通知。
- SignalR 提供用於創建服務器到客戶端遠程過程調用 (RPC) 的 API。 RPC 從服務器端 .NET Core 代碼調用客戶端上的函數。 提供多個受支持的平臺,其中每個平臺都有各自的客戶端 SDK。 因此,RPC 調用所調用的編程語言有所不同。
以下是 ASP.NET Core SignalR 的一些功能:
- 自動處理連接管理。
- 同時向所有連接的客戶端發送消息。 例如聊天室。
- 向特定客戶端或客戶端組發送消息。
- 對其進行縮放,以處理不斷增加的流量。
傳輸
SignalR 支持以下用於處理實時通信的技術(按正常回退的順序):
- WebSockets
- Server-Sent Events
- 長輪詢
SignalR 自動選擇服務器和客戶端能力範圍內的最佳傳輸方法。
中心
SignalR 使用中心在客戶端和服務器之間進行通信。
Hub 是一種高級管道,允許客戶端和服務器相互調用方法。 SignalR 自動處理跨計算機邊界的調度,並允許客戶端調用服務器上的方法,反之亦然。 可以將強類型參數傳遞給方法,從而支持模型綁定。 SignalR 提供兩種內置中心協議:基於 JSON 的文本協議和基於 MessagePack 的二進制協議。 與 JSON 相比,MessagePack 通常會創建更小的消息。 舊版瀏覽器必須支持 XHR 級別 2 才能提供 MessagePack 協議支持。
中心通過發送包含客戶端方法的名稱和參數的消息來調用客戶端代碼。 作爲方法參數發送的對象使用配置的協議進行反序列化。 客戶端嘗試將名稱與客戶端代碼中的方法匹配。 當客戶端找到匹配項時,它會調用該方法並將反序列化的參數數據傳遞給它。
在升訊威客服系統中使用 SignalR
創建 SignalR 中心
中心是一個類,用作處理客戶端 - 服務器通信的高級管道。
在 SignalRChat 項目文件夾中,創建 Hubs 文件夾。
在 Hubs 文件夾中,使用以下代碼創建 ChatHub 類:
using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
ChatHub 類繼承自 SignalRHub。 Hub 類管理連接、組和消息。
可通過已連接客戶端調用 SendMessage,以向所有客戶端發送消息。 本教程後面部分將顯示調用該方法的 JavaScript 客戶端代碼。 SignalR 代碼是異步模式,可提供最大的可伸縮性。
配置 SignalR
必須將 SignalR 服務器配置爲將 SignalR 請求傳遞給 SignalR。 將以下突出顯示的代碼添加到 Program.cs 文件。
using SignalRChat.Hubs;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
app.Run();
以上突出顯示的代碼將 SignalR 添加到 ASP.NET Core 依賴關係注入和路由系統。
添加 SignalR 客戶端代碼
- 創建並啓動連接。
- 向“提交”按鈕添加一個用於向中心發送消息的處理程序。
- 向連接對象添加一個用於從中心接收消息並將其添加到列表的處理程序。
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
//Disable the send button until connection is established.
document.getElementById("sendButton").disabled = true;
connection.on("ReceiveMessage", function (user, message) {
var li = document.createElement("li");
document.getElementById("messagesList").appendChild(li);
// We can assign user-supplied strings to an element's textContent because it
// is not interpreted as markup. If you're assigning in any other way, you
// should be aware of possible script injection concerns.
li.textContent = `${user} says ${message}`;
});
connection.start().then(function () {
document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
return console.error(err.toString());
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
當從 Hub 類外部調用客戶端方法時,沒有與該調用關聯的調用方。 因此,無法訪問 ConnectionId、Caller 和 Others 屬性。
需要將用戶映射到連接 ID 並保留該映射的應用可以執行以下操作之一:
- 將單個或多個連接的映射保留爲組。 有關詳細信息,請參閱SignalR 中的組。
- 通過單一實例服務保留連接和用戶信息。 有關詳細信息,請參閱將服務注入中心。 單一實例服務可以使用任何存儲方法,例如:
- 字典中的內存中存儲。
- 永久性外部存儲。 例如,使用 Azure.Data.Tables NuGet 包的數據庫或 Azure 表存儲。
- 在客戶端之間傳遞連接 ID。
從 IHost 獲取 IHubContext 實例
從 Web 主機訪問 IHubContext 對於與 ASP.NET Core 之外的區域集成很有用,例如,使用第三方依賴項注入框架:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
});
}
SignalR 中的單個用戶可以與一個應用建立多個連接。 例如,用戶可以在桌面和手機上進行連接。 每臺設備都有一個單獨的 SignalR 連接,但它們都與同一個用戶關聯。 如果向用戶發送消息,則與該用戶關聯的所有連接都會收到消息。 可以通過中心內的 Context.UserIdentifier 屬性訪問連接的用戶標識符。
默認情況下,SignalR 使用與連接關聯的 ClaimsPrincipal 中的 ClaimTypes.NameIdentifier 作爲用戶標識符。 若要自定義此行爲,請參閱使用聲明自定義標識處理。
重新連接時不會保留組成員身份。 重新建立連接後,需要重新加入組。 無法計算組的成員數,因爲如果將應用程序擴展到多臺服務器,則無法獲取此信息。
若要在使用組時保護對資源的訪問,請使用 ASP.NET Core 中的身份驗證和授權功能。 如果僅當憑據對組有效時纔將用戶添加到該組,則發送到該組的消息將僅發送給授權用戶。 但是,組不是一項安全功能。 身份驗證聲明具有組不具備的功能,例如到期和撤銷。 如果撤銷用戶對組的訪問權限,應用必須從組中顯式刪除該用戶。
簡介
升訊威在線客服與營銷系統是一款客服軟件,但更重要的是一款營銷利器。
- 可以追蹤正在訪問網站或使用 APP 的所有訪客,收集他們的瀏覽情況,使客服能夠主動出擊,施展話術,促進成單。
訪* 客端在 PC 支持所有新老瀏覽器。包括不支持 WebSocket 的 IE8 也能正常使用。 - 移動端支持所有手機瀏覽器、APP、各大平臺的公衆號對接。
- 支持訪客信息互通,可傳輸訪客標識、名稱和其它任意信息到客服系統。
- 具備一線專業技術水平,網絡中斷,拔掉網線,手機飛行模式,不丟消息。同類軟件可以按視頻方式對比測試。
-
- bilibili 視頻:https://www.bilibili.com/video/BV1pK4y1N7UP?t=22