下面是一個簡單的 SignalR Hub 示例,包括服務器端和客戶端的基本配置與使用說明。
1. 服務器端
a. 建立 Hub 類別
首先,在 v2knowBlazor(Server)專案中新增一個 SignalR Hub 類別,例如 ChatHub.cs
:
using Microsoft.AspNetCore.SignalR;
public class ChatHub : Hub
{
// 一個簡單的方法:收到消息後轉發給所有連接的客戶端
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
這個 Hub 定義了一個 SendMessage
方法,當客戶端呼叫該方法時,服務器會透過 Clients.All.SendAsync
把消息發送給所有連接的客戶端。
b. 在 Program.cs 中註冊並映射 Hub
在 v2knowBlazor 的 Program.cs
裡面,新增 SignalR 服務並映射 Hub 端點:
var builder = WebApplication.CreateBuilder(args);
// 註冊 SignalR 服務
builder.Services.AddSignalR();
// 其它服務與中間件配置
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
// ... 其他註冊與配置代碼
var app = builder.Build();
// 中間件配置,如錯誤處理、靜態文件、路由等
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// 映射 SignalR Hub 端點
app.MapHub<ChatHub>("/chathub");
// 映射 Razor 組件(Blazor 頁面)等
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(v2knowBlazor.Client._Imports).Assembly);
app.Run();
這裏透過 builder.Services.AddSignalR();
添加 SignalR 相關服務,並使用 app.MapHub<ChatHub>("/chathub");
將 Hub 映射到指定端點(這裡是 /chathub
)。
2. 客戶端
在 v2knowBlazor.Client 專案中,你可以使用 SignalR 客戶端庫來建立連線。假設你在某個 Razor 組件中(例如 Pages/Chat.razor
)使用 SignalR 連線:
a. 安裝 NuGet 套件
確保你的客戶端專案中安裝了 SignalR 客戶端套件:
dotnet add package Microsoft.AspNetCore.SignalR.Client
b. 示例 Razor 組件(Chat.razor)
@page "/chat"
@using Microsoft.AspNetCore.SignalR.Client
@inject NavigationManager Navigation
@rendermode InteractiveAuto
<h3>Chat</h3>
<input @bind="user" placeholder="Your name" />
<input @bind="message" placeholder="Message" />
<button @onclick="Send">Send</button>
<ul>
@foreach (var msg in messages)
{
<li>@msg</li>
}
</ul>
@code {
private HubConnection? hubConnection;
private string user = string.Empty;
private string message = string.Empty;
private List<string> messages = new();
protected override async Task OnInitializedAsync()
{
// 建立 Hub 連線(注意使用 Navigation.BaseUri 拼出完整 URL)
hubConnection = new HubConnectionBuilder()
.WithUrl(Navigation.ToAbsoluteUri("/chathub"))
.WithAutomaticReconnect()
.Build();
// 註冊從服務器接收消息的處理函數
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
var encodedMsg = $"{user}: {message}";
messages.Add(encodedMsg);
InvokeAsync(StateHasChanged);
});
await hubConnection.StartAsync();
}
private async Task Send()
{
if (hubConnection is not null)
{
await hubConnection.SendAsync("SendMessage", user, message);
message = string.Empty;
}
}
public bool IsConnected =>
hubConnection is not null && hubConnection.State == HubConnectionState.Connected;
public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
{
await hubConnection.DisposeAsync();
}
}
}
在這個範例中:
- 我們先建立一個
HubConnection
並指定連線的 URL (/chathub
),該 URL 與服務器端在Program.cs
中映射的端點一致。 - 使用
hubConnection.On<string, string>("ReceiveMessage", ...)
註冊從服務器接收消息的事件處理程式。 - 當用戶在 UI 中輸入資料並點擊 Send 按鈕時,呼叫
SendMessage
方法,將訊息發送到服務器端,後者再分發給所有連線的用戶。
總結
這個簡單示例展示了如何在服務器端建立一個 SignalR Hub,並在客戶端(Blazor WASM)連線、接收與發送消息。這種模式可應用於聊天應用、即時通知、遊戲或其它需要實時通信的場景。
直接訪問/chathub會出現Connection ID required, 這個URL相當於API?會被濫用嗎?需要令牌嗎?
當你直接在瀏覽器中訪問
/chathub
時,看到“Connection ID required”訊息,這其實是正常現象。這是因為 SignalR Hub 的端點並非傳統意義上的 HTTP API,而是一個用來建立持久連線(如 WebSocket 或長輪詢)的通信管道。以下是針對你的幾個問題的詳細解釋:
1.
/chathub
是 API 嗎?
- 不是傳統 API:
/chathub
端點不是用來直接發送 HTTP 請求並獲取資料的 API,而是專門用來建立持久連線的。當 SignalR 客戶端(例如在 Blazor 應用中)嘗試建立連線時,它會發起握手(handshake)請求,並根據不同的協議(例如 WebSocket、長輪詢等)來維護連線。- 直接訪問無法使用:直接在瀏覽器中輸入
/chathub
會得到類似「Connection ID required」的提示,這是因為請求並未經過正確的 SignalR 握手流程。
2. 會被濫用嗎?
- 暴露端點風險:在理論上,所有公開的端點都有可能遭受惡意請求。不過 SignalR Hub 端點並不是傳統靜態 API,而是需要經過握手與協議協商才能使用。若沒有正確的連線握手,請求會被拒絕或返回錯誤訊息。
- 防範措施:如果應用中存在較高的安全需求或擔心惡意濫用,可以考慮如下做法:
- 身份驗證與授權:在 Hub 中實現授權機制,例如使用
Hub
的Authorize
屬性來限制只有經過授權的用戶才能連線。- 令牌驗證:透過配置 SignalR 連線時,客戶端可以附加 JWT 或其它令牌,服務器端在建立連線時進行驗證。這樣即使有人直接訪問
/chathub
,也無法通過身份驗證。- 限流與防火牆:若應用面臨大流量或潛在攻擊風險,可能需要進一步的 IP 限流或應用層防火牆來保護 SignalR 端點。
3. 是否需要令牌?
- 根據需求決定:預設情況下,SignalR Hub 並不自動要求令牌。如果你的應用存在敏感操作或數據,建議採用身份驗證與授權機制:
你可以在 SignalR Hub 類別上加上
[Authorize]
屬性,這樣只有已通過授權的用戶才能建立連線。客戶端在建立連線時,可以配置附加令牌。例如(以 JWT 為例):
hubConnection = new HubConnectionBuilder() .WithUrl(Navigation.ToAbsoluteUri("/chathub"), options => { options.AccessTokenProvider = () => Task.FromResult("your-jwt-token-here"); }) .WithAutomaticReconnect() .Build();
服務器端在授權時會檢查這個令牌,確保連線合法。
總結
- /chathub 端點實際上是供 SignalR 客戶端建立持久連線的管道,而不是傳統意義上的 API。
- 直接訪問會因為缺少握手信息而返回錯誤(如 "Connection ID required")。
這樣一來,你既能利用 SignalR 實現實時雙向通信,又能保障應用的安全性。
- 安全性:如果擔心被濫用,可以在 Hub 上實施身份驗證與授權機制,並考慮使用令牌進行進一步保護。