ASP.NET Core SignalR (十)【下】:SignalR Javascript 客户端
此为系列文章,对MSDN ASP.NET Core SignalR 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。
错误处理以及日志
在start 方法的后面链接一个catch 方法来处理客户端的错误。output.error将错误输出到浏览器控制台。
*/ /* this is here to show another alternative to start, with a catch
当连接建立的时候,可以通过传递一个日志记录器及一种类型的事件给日志记录器来建立客户端的日志追踪。消息以特定的日志级别被记录。如下是可用的日志级别:
- 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();
重连客户端
自动重连
使用 HubConnectionBuilder 上的withAutomaticReconnect方法,可以将 SignalR Javascript 客户端配置为自动重连。默认情况下其不会自动重连。
const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .withAutomaticReconnect() .build();c
如果不带任何参数,withAutomaticReconnect 会配置客户端在每一次重连尝试之前,分别等待0,2,10,30秒,如果四次重连均失败,那么连接便会停止。
如果配置了自动重连,在开始每一次重连尝试之前,HubConnection 都会变为 HubConnectionState.Reconnecting 状态并触发它的onreconnecting 回调。而如果没有配置HubConnection 为自动重连,此时(连接断开时)HubConnection 的状态会变为Disconnected
并触发它的onclose
回调。这就提供了一个时机来警告用户连接已经丢失,并禁用掉相关的UI元素。
connection.onreconnecting((error) => { console.assert(connection.state === signalR.HubConnectionState.Reconnecting); document.getElementById("messageInput").disabled = true; const li = document.createElement("li"); li.textContent = `Connection lost due to error "${error}". Reconnecting.`; document.getElementById("messagesList").appendChild(li); });
如果客户端在它的前四次重连尝试之内成功连接,HubConnection 会重新变回Connected
状态并触发它的onreconnected 回调。这提供了一个时机来通知用户连接已经重新建立。
注意,如果HubConnection
被配置为 skip negotiation,那么onreconnected 回调的 connectionId参数将会是 underfined。
connection.onreconnected((connectionId) => { console.assert(connection.state === signalR.HubConnectionState.Connected); document.getElementById("messageInput").disabled = false; const li = document.createElement("li"); li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`; document.getElementById("messagesList").appendChild(li); });
如果初始的启动失败了,withAutomaticReconnect 不会配置HubConnection 来重试,因此,启动失败需要手动处理。
async function start() { try { await connection.start(); console.assert(connection.state === signalR.HubConnectionState.Connected); console.log("connected"); } catch (err) { console.assert(connection.state === signalR.HubConnectionState.Disconnected); console.log(err); setTimeout(() => start(), 5000); } };
如果在前四次尝试之内,客户端都没有重连成功的话,HubConnection
会过渡到Disconnected状态并触发其 onclose 回调。这提供了一个时机来通知用户连接已经永久丢失了,并建议刷新页面。
connection.onclose((error) => { console.assert(connection.state === signalR.HubConnectionState.Disconnected); document.getElementById("messageInput").disabled = true; const li = document.createElement("li"); li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`; document.getElementById("messagesList").appendChild(li); });
为了在断开连接或者更改重连间隔之前配置一个自定义的重连数,withAutomaticReconnect
接收一个数字数组,其以毫秒数表示了在进行每一次重连尝试之前所需要等待的时间。
const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .withAutomaticReconnect([0, 0, 10000]) .build(); // .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
如上的示例配置了HubConnection
在连接丢失之后立即开始尝试重连。这和默认配置是一致的。
如果第一次重连尝试失败了,第二次重连尝试也会立即开始,而并不会像默认配置那样等待2秒。
如果第二个重连尝试失败了,第三次重连尝试会在10秒内开始,这又和默认配置保持一致。
在第三次重连尝试失败之后,连接便会停止,此刻,自定elapsedMilliseconds义行为和默认行为便产生了相背离。在默认配置中,还会在30秒之后再次发出一次重连尝试。
如果你对于时间和自动重连的次数想要有更多的控制,withAutomaticReconnect 可以接收一个实现了IRetryPolicy 接口的对象,其有一个单独的方法名为 nextRetryDelayInMilliseconds。
nextRetryDelayInMilliseconds 带有一个单独的类型为 RetryContext 的参数。RetryContext
具有三个属性:previousRetryCount,elapsedMilliseconds,retryReason,其类型分别是 number,number,Error。在第一次重连尝试之前,previousRetryCount 和elapsedMilliseconds 都会是0,而retryReason会是导致连接丢失的那个Error。而在每一次重连尝试失败之后,previousRetryCount将会自增1,elapsedMilliseconds将会被更新,以毫秒的形式反映了到现在为止花费在重连上的时间。而retryReason 将会是导致上一次重连尝试失败的Error。
nextRetryDelayInMilliseconds
要么返回一个表示在下一次重连之前等待的毫秒数,要么返回一个null。如果返回一个null,则表示HubConnection应该停止重连。
const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .withAutomaticReconnect({ nextRetryDelayInMilliseconds: retryContext => { if (retryContext.elapsedMilliseconds < 60000) { // If we've been reconnecting for less than 60 seconds so far, // wait between 0 and 10 seconds before the next reconnect attempt. return Math.random() * 10000; } else { // If we've been reconnecting for more than 60 seconds so far, stop reconnecting. return null; } } }) .build();
或者,你也可以编写代码来手动重连你的客户端,如下个章节所示。
手动重连
如下代码演示了一个经典的手动重连实现:
- 创建了一个函数(start)来启动连接。
- 在连接的onclose 事件处理中调用 start 函数。
async function start() { try { await connection.start(); console.log("connected"); } catch (err) { console.log(err); setTimeout(() => start(), 5000); } }; connection.onclose(async () => { await start(); });
在现实世界中,将会使用指数回退,或者重试指定的次数。如果均连接失败,那么便会停止连接尝试。
额外资源