本章將和大家分享 ASP.NET Core SignalR 中的 JavaScript 客戶端。ASP.NET Core SignalR JavaScript 客戶端庫使開發人員能夠調用伺服器端SignalR中心代碼。 ...
本章將和大家分享 ASP.NET Core SignalR 中的 JavaScript 客戶端。ASP.NET Core SignalR JavaScript 客戶端庫使開發人員能夠調用伺服器端SignalR中心代碼。
本文大部分內容摘自微軟官網:https://learn.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-7.0&tabs=visual-studio
廢話不多說,下麵我們直接進入本章主題:
1、安裝 SignalR 客戶端包
ASP.NET Core 共用框架中包含 SignalR 伺服器庫。JavaScript 客戶端庫不會自動包含在項目中。對於此教程,使用庫管理器 (LibMan) 從 unpkg 獲取客戶端庫。unpkg 是一個快速的全局內容分髮網絡,適用於 npm 上的所有內容。
在 Visual Studio “解決方案資源管理器” 中,右鍵單擊項目,然後選擇 “添加” => “客戶端庫”。
在“添加客戶端庫”對話框中:
- 為“提供程式”選擇“unpkg”。
- 對於“庫”,請輸入 @microsoft/signalr@latest。
- 選擇“選擇特定文件”,展開“dist/browser”文件夾,然後選擇 signalr.js 和 signalr.min.js。
- 將“目標位置”設置為 wwwroot/js/signalr/。(可根據實際情況進行修改)
- 選擇“安裝” 。
LibMan 會創建 wwwroot/js/signalr 文件夾並將所選文件複製到該文件夾下。
2、連接到中心
以下代碼創建並啟動連接。中心的名稱不區分大小寫:
//第一個參數:載入依賴模塊,可以是require_config中定義的短模塊名,也可以是完整的模塊路徑(去掉.js尾碼名,根目錄為require_config中設置的baseUrl) //第二個參數:執行載入完後的回調函數 require(['../common/base', 'jquery', 'signalr'], function (base, $, signalR) { let axios = base.axios; var vm = new base.vue({ el: '#app', //掛載點 mixins: [base.mixin], //混入,類似基類的概念 data: { connectionSignalR: '', //SignalR連接 user: '', message: '', msgList: [] }, //created鉤子函數 created: function () { this.initSignalR(); //初始化SignalR }, //mounted鉤子函數 mounted: function () { //console.log('This is index mounted'); }, //方法 methods: { //初始化SignalR initSignalR: function () { var _this = this; var domain = "http://localhost:5296"; //網站功能變數名稱 //創建連接 _this.connectionSignalR = new signalR.HubConnectionBuilder() .withUrl(domain + "/chatHub") //跨域的話必須使用絕對路徑 .configureLogging(signalR.LogLevel.Error) //配置日誌等級 //自動重新連接,嘗試每次重新連接之前預設分別等待 0、2、10 和 30 秒。嘗試四次失敗後,它會停止嘗試重新連接。 .withAutomaticReconnect() //.withAutomaticReconnect([0, 2000, 10000, 30000]) .build(); /* 日誌等級: signalR.LogLevel.Error:錯誤消息。 Error僅記錄消息。 signalR.LogLevel.Warning:有關潛在錯誤的警告消息。 日誌 Warning 和 Error 消息。 signalR.LogLevel.Information:無錯誤的狀態消息。 日誌 Information 、 Warning 和 Error 消息。 signalR.LogLevel.Trace:跟蹤消息。 記錄所有內容,包括中心和客戶端之間傳輸的數據。 */ //監聽中心(服務端)發送的消息(服務端調用客戶端)(訂閱) //ReceiveMessage 是服務端調用客戶端的方法名 _this.connectionSignalR.on("ReceiveMessage", function (user, message) { _this.msgList.push({ user: user, message: message }); }); //啟動連接 _this.connectionSignalR.start().then(function () { //啟動連接後需要立即執行的邏輯 //document.getElementById("sendButton").disabled = false; }).catch(function (err) { return console.error(err.toString()); }); }, //發送消息 sendMsg: function () { var _this = this; if (_this.message) { //向中心(服務端)發送消息(客戶端調用服務端) //SendMessage 是服務端定義的的方法 _this.connectionSignalR.invoke("SendMessage", _this.user, _this.message).catch(function (err) { return console.error(err.toString()); }); _this.message = ''; //發送完清空消息 } }, } }); });
3、跨域連接(CORS)
通常,瀏覽器從與請求頁面相同的域載入連接。但是,有時需要連接到另一個域。
發出跨域請求時,客戶端代碼必須使用絕對 URL 而不是相對 URL。對於跨域請求,需要將 .withUrl("/chathub") 修改為 .withUrl("https://{App domain name}/chathub") 。
為了防止惡意站點從另一站點讀取敏感數據,預設情況下禁用跨域連接。若要允許跨源請求,請啟用 CORS:
using SignalRChat.Hubs; namespace SignalRChat { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); //服務註冊(往容器中添加服務) // Add services to the container. builder.Services.AddControllersWithViews(); builder.Services.AddSignalR(); //註冊中心所需的 SignalR 服務 //設置允許跨域 builder.Services.AddCors(options => { options.AddDefaultPolicy( builder => { builder.WithOrigins("http://localhost:5296", "http://localhost:8080") .AllowAnyHeader() .WithMethods("GET", "POST") .AllowCredentials(); }); }); var app = builder.Build(); //配置Http請求處理管道 // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); //設置允許跨域 // UseCors must be called before MapHub. //必須在 MapHub 之前調用 UseCors 方法 app.UseCors(); //配置MVC路由 app.MapControllerRoute( name: "areas", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); //配置SignalR終結點 app.MapHub<ChatHub>("/chatHub"); //中心 app.MapHub<StronglyTypedChatHub>("/stronglyTypedChatHub"); //強類型中心 app.Run(); } } }
必須在 MapHub 之前調用 app.UseCors(); 方法。
4、從客戶端調用中心方法
JavaScript 客戶端通過 HubConnection 的 invoke 方法調用中心的公共方法。invoke 方法接受:
- 中心方法的名稱。
- 中心方法中定義的任何參數。
在以下突出顯示的代碼中,中心上的方法名稱為 SendMessage
。傳遞到 invoke
的第二個和第三個參數映射到中心方法的 user
和 message
參數:
try { await connection.invoke("SendMessage", user, message); } catch (err) { console.error(err); }
僅在預設模式下使用 Azure SignalR 服務 時,才支持從客戶端調用中心方法。
invoke 方法返回 JavaScript Promise。 伺服器上的方法返回時,Promise 通過返回值(如果有)進行解析。如果伺服器上的方法引發錯誤,Promise 會被拒絕並顯示錯誤消息。使用 async 和 await 或 Promise 的 then 和 catch 方法來處理這些情況。
JavaScript 客戶端還可以通過 HubConnection 的 send 方法調用中心的公共方法。與 invoke 方法不同,send 方法不會等待來自伺服器的響應。send 方法返回 JavaScript Promise。當消息發送到伺服器後,會解析 Promise。如果發送消息時出錯,Promise 會被拒絕並顯示錯誤消息。使用 async 和 await 或 Promise 的 then 和 catch 方法來處理這些情況。
使用 send 不會等到伺服器收到消息。因此,無法從伺服器返回數據或錯誤。
5、從中心調用客戶端方法
若要接收來自中心的消息,請使用 HubConnection 的 on 方法定義方法:
- JavaScript 客戶端方法的名稱。
- 中心傳遞給方法的參數。
在下麵的示例中,方法名稱為 ReceiveMessage。參數名稱為 user 和 message:
connection.on("ReceiveMessage", (user, message) => { const li = document.createElement("li"); li.textContent = `${user}: ${message}`; document.getElementById("messageList").appendChild(li); });
connection.on 中的上述代碼在伺服器端代碼使用 SendAsync 方法調用它時運行:
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); } }
SignalR 通過匹配在 SendAsync 和 connection.on 中定義的方法名稱和參數來確定要調用的客戶端方法。
客戶端的最佳做法是在 on 之後 調用 HubConnection 的 start 方法。這樣做可確保在收到任何消息之前註冊處理程式。
6、錯誤處理和日誌記錄
使用 console.error 在客戶端無法連接或發送消息時將錯誤輸出到瀏覽器的控制台:
try { await connection.invoke("SendMessage", user, message); } catch (err) { console.error(err); }
在建立連接時,通過傳遞記錄器和要記錄的事件類型來設置客戶端日誌跟蹤。可用的日誌級別如下所示:
- signalR.LogLevel.Error:錯誤消息。僅記錄 Error 消息。
- signalR.LogLevel.Warning:有關潛在錯誤的警告消息。記錄 Warning 和 Error 消息。
- signalR.LogLevel.Information:沒有錯誤的狀態消息。記錄 Information、Warning 和 Error 消息。
- signalR.LogLevel.Trace:跟蹤消息。記錄所有內容,包括在中心和客戶端之間傳輸的數據。
使用 HubConnectionBuilder 上的 configureLogging 方法配置日誌級別。消息將記錄到瀏覽器控制台:
const connection = new signalR.HubConnectionBuilder() .withUrl("/chathub") .configureLogging(signalR.LogLevel.Information) .build();
7、重新連接客戶端
1)自動重新連接
預設情況下,它不會自動重新連接。如果需要自動重新連接,則可以將 SignalR 的 JavaScript 客戶端配置為使用 HubConnectionBuilder 上的 WithAutomaticReconnect 方法。
const connection = new signalR.HubConnectionBuilder() .withUrl("/chathub") .withAutomaticReconnect() .build();
如果不使用任何參數,WithAutomaticReconnect 會將客戶端配置為每次嘗試重新連接之前分別等待 0、2、10 和 30 秒。嘗試四次失敗後,會停止嘗試重新連接。
配置自定義的重新連接嘗試次數,withAutomaticReconnect 會接受一個數字數組,表示在每次開始嘗試重新連接之前要等待的延遲(以毫秒為單位):
const connection = new signalR.HubConnectionBuilder() .withUrl("/chathub") .withAutomaticReconnect([0, 0, 10000]) .build(); // .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
若要更好地控制自動重新連接嘗試的時間和次數,可以自行去微軟官網瞭解。
2)手動重新連接
下麵的代碼演示典型的手動重新連接方法:
- 創建函數(在本例中為 start 函數)以啟動連接。
- 在連接的 onclose 事件處理程式中調用 start 函數。
async function start() { try { await connection.start(); console.log("SignalR Connected."); } catch (err) { console.log(err); setTimeout(start, 5000); } }; connection.onclose(async () => { await start(); });
生產實現通常使用指數退避或重試指定的次數。
8、瀏覽器睡眠選項卡
某些瀏覽器具有選項卡凍結或休眠功能,用於減少非活動選項卡的電腦資源使用量。 這可能會導致 SignalR 連接關閉,並可能導致不必要的用戶體驗。
瀏覽器使用啟發法判斷選項卡是否應進入睡眠狀態,下麵的代碼示例演示如何使用 Web Lock 將選項卡保持為喚醒狀態,並避免意外的連接關閉:
var lockResolver; if (navigator && navigator.locks && navigator.locks.request) { const promise = new Promise((res) => { lockResolver = res; }); navigator.locks.request('unique_lock_name', { mode: "shared" }, () => { return promise; }); }
對於上述代碼示例:
- Web Lock 是實驗性的。條件檢查可確認瀏覽器是否支持 Web Lock。
- 存儲承諾解析程式 lockResolver,以便在選項卡進入睡眠狀態時可以釋放鎖。
- 關閉連接時,通過調用 lockResolver() 釋放鎖定。釋放鎖定時,選項卡可進入睡眠狀態。
9、SignalR 信息推送的兩種通道
1)客戶端觸發推送,如下所示:
2)服務端觸發推送,如下所示:
至此本文就全部介紹完了,想要瞭解更多內容可參考微軟官網。
Demo源碼:
鏈接:https://pan.baidu.com/s/1U4IadFp-qThj0t3axrtNJA 提取碼:bwb3
此文由博主精心撰寫轉載請保留此原文鏈接:https://www.cnblogs.com/xyh9039/p/17539560.html
版權聲明:如有雷同純屬巧合,如有侵權請及時聯繫本人修改,謝謝!!!