我在業餘時間開發維護了一款免費開源的升訊威線上客服系統,也收穫了許多使用者。對我來說,只要能獲得使用者的認可,就是我最大的動力。
最近客服系統成功經受住了客戶現場組織的壓力測試,獲得了客戶的認可。
客戶組織多名客服上線後,所有員工同一時間開啟訪客頁面瘋狂不停的給線上客服發訊息,系統穩定無異常無掉線,客服回覆訊息正常。訊息實時到達無任何延遲。
我會通過一系列的文章詳細分析升訊威線上客服系統的並行高效能技術是如何實現的,使用了哪些方案以及具體的做法。
本篇介紹超強的 SignalR 技術。
ASP.NET Core SignalR 是一個開放原始碼庫,可用於簡化嚮應用新增實時 Web 功能。 實時 Web 功能使伺服器端程式碼能夠將內容推播到使用者端。
適合 SignalR 的候選項:
以下是 ASP.NET Core SignalR 的一些功能:
SignalR 支援以下用於處理實時通訊的技術(按正常回退的順序):
SignalR 自動選擇伺服器和使用者端能力範圍內的最佳傳輸方法。
SignalR 使用中心在使用者端和伺服器之間進行通訊。
Hub 是一種高階管道,允許使用者端和伺服器相互呼叫方法。 SignalR 自動處理跨計算機邊界的排程,並允許使用者端呼叫伺服器上的方法,反之亦然。 可以將強型別引數傳遞給方法,從而支援模型繫結。 SignalR 提供兩種內建中心協定:基於 JSON 的文字協定和基於 MessagePack 的二進位制協定。 與 JSON 相比,MessagePack 通常會建立更小的訊息。 舊版瀏覽器必須支援 XHR 級別 2 才能提供 MessagePack 協定支援。
中心通過傳送包含使用者端方法的名稱和引數的訊息來呼叫使用者端程式碼。 作為方法引數傳送的物件使用設定的協定進行反序列化。 使用者端嘗試將名稱與使用者端程式碼中的方法匹配。 當用戶端找到匹配項時,它會呼叫該方法並將反序列化的引數資料傳遞給它。
中心是一個類,用作處理使用者端 - 伺服器通訊的高階管道。
在 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。 將以下突出顯示的程式碼新增到 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 依賴關係注入和路由系統。
"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 並保留該對映的應用可以執行以下操作之一:
從 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 中的身份驗證和授權功能。 如果僅當憑據對組有效時才將使用者新增到該組,則傳送到該組的訊息將僅傳送給授權使用者。 但是,組不是一項安全功能。 身份驗證宣告具有組不具備的功能,例如到期和復原。 如果復原使用者對組的存取許可權,應用必須從組中顯式刪除該使用者。
升訊威線上客服與行銷系統是一款客服軟體,但更重要的是一款行銷利器。