如何在生产中部署 Blazor 服务器并克服 SignalR 重连问题?
How to deploy Blazor server in production and overcome SignalR re-connection problems?
Blazor 服务器是一项了不起的技术,但它经常因 SignalR 无法重新连接到服务器而中断。
如何在生产中解决这个问题?我让人们让他们的笔记本电脑进入睡眠状态,或者让 phone 与网站保持 5 秒的距离,而不是 - "Attempting to reconnect".
而且总是失败。用户等待只是为了看到 "Reload" 按钮。
如何克服这个问题并强制重新连接 SignalR,即使网站在移动浏览器或休眠电脑的浏览器中不活跃?
概览
Blazor 内置了用于自定义启动过程的选项,但它们并没有得到很好的记录。
据我所知就是这样:Configure the SignalR client for Blazor Server apps
但是还有更多选项,包括设置重新连接选项的能力。
样本
在下面的代码示例中,我设置了 maxRetries 和 retryIntervalMilliseconds(第 48/49 行)——它们定义了客户端在通信中断时尝试重新连接的积极程度。
我还配置了一个自定义的 reconnectionHandler(第 51 行),它具有一个最小的实现,它将尝试重新连接(不显示任何 UI),如果所有尝试都失败,它只会重新加载页面。
这不是一件特别聪明的事情,但它可以作为一个示例来演示您可以如何着手自定义流程。
进一步阅读
AspNetCore Circuits Client Side Code
** 请不要在生产中使用此示例 - 它仅供参考 **
首先,使用 autostart="false"
关闭 Blazor 启动进程
<script autostart="false" src="_framework/blazor.server.js"></script>
然后,您可以提供自己的连接处理程序和设置
<script>
async function connectionDown(options) {
console.log("Connection Down - you could do some UI here...");
for (let i = 0; i < options.maxRetries; i++) {
console.log("Waiting for reconnect attempt #"+(i+1)+" ...");
await this.delay(options.retryIntervalMilliseconds);
if (this.isDisposed) {
break;
}
try {
// reconnectCallback will asynchronously return:
// - true to mean success
// - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID)
// - exception to mean we didn't reach the server (this can be sync or async)
console.log("Starting Reconnect attempt #"+(i+1)+" ...");
const result = await window.Blazor.reconnect();
if (!result) {
// If the server responded and refused to reconnect, log it
console.error("Server Rejected");
} else {
// Reconnected!
return;
}
} catch (err) {
// We got an exception so will try again
console.error(err);
}
}
// all attempts failed - let's try a full reload
// This could be a UI change instead or something more complicated
location.reload();
}
function delay(durationMilliseconds) {
return new Promise(resolve => setTimeout(resolve, durationMilliseconds));
}
function connectionUp(e) {
// Reconnected
console.log("Connection UP!");
// if you have a UI to hide/change you can do that here.
}
window.Blazor.start({
reconnectionOptions: {
maxRetries: 30,
retryIntervalMilliseconds: 500,
},
reconnectionHandler: {
onConnectionDown: e => connectionDown(e),
onConnectionUp: e => connectionUp(e)
}
});
</script>
Blazor 服务器是一项了不起的技术,但它经常因 SignalR 无法重新连接到服务器而中断。
如何在生产中解决这个问题?我让人们让他们的笔记本电脑进入睡眠状态,或者让 phone 与网站保持 5 秒的距离,而不是 - "Attempting to reconnect".
而且总是失败。用户等待只是为了看到 "Reload" 按钮。
如何克服这个问题并强制重新连接 SignalR,即使网站在移动浏览器或休眠电脑的浏览器中不活跃?
概览
Blazor 内置了用于自定义启动过程的选项,但它们并没有得到很好的记录。
据我所知就是这样:Configure the SignalR client for Blazor Server apps
但是还有更多选项,包括设置重新连接选项的能力。
样本
在下面的代码示例中,我设置了 maxRetries 和 retryIntervalMilliseconds(第 48/49 行)——它们定义了客户端在通信中断时尝试重新连接的积极程度。
我还配置了一个自定义的 reconnectionHandler(第 51 行),它具有一个最小的实现,它将尝试重新连接(不显示任何 UI),如果所有尝试都失败,它只会重新加载页面。
这不是一件特别聪明的事情,但它可以作为一个示例来演示您可以如何着手自定义流程。
进一步阅读 AspNetCore Circuits Client Side Code
** 请不要在生产中使用此示例 - 它仅供参考 **
首先,使用autostart="false"
关闭 Blazor 启动进程
<script autostart="false" src="_framework/blazor.server.js"></script>
然后,您可以提供自己的连接处理程序和设置
<script>
async function connectionDown(options) {
console.log("Connection Down - you could do some UI here...");
for (let i = 0; i < options.maxRetries; i++) {
console.log("Waiting for reconnect attempt #"+(i+1)+" ...");
await this.delay(options.retryIntervalMilliseconds);
if (this.isDisposed) {
break;
}
try {
// reconnectCallback will asynchronously return:
// - true to mean success
// - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID)
// - exception to mean we didn't reach the server (this can be sync or async)
console.log("Starting Reconnect attempt #"+(i+1)+" ...");
const result = await window.Blazor.reconnect();
if (!result) {
// If the server responded and refused to reconnect, log it
console.error("Server Rejected");
} else {
// Reconnected!
return;
}
} catch (err) {
// We got an exception so will try again
console.error(err);
}
}
// all attempts failed - let's try a full reload
// This could be a UI change instead or something more complicated
location.reload();
}
function delay(durationMilliseconds) {
return new Promise(resolve => setTimeout(resolve, durationMilliseconds));
}
function connectionUp(e) {
// Reconnected
console.log("Connection UP!");
// if you have a UI to hide/change you can do that here.
}
window.Blazor.start({
reconnectionOptions: {
maxRetries: 30,
retryIntervalMilliseconds: 500,
},
reconnectionHandler: {
onConnectionDown: e => connectionDown(e),
onConnectionUp: e => connectionUp(e)
}
});
</script>