клиент JavaScript ASP.NET Core SignalR
Автор: Рэйчел Аппель (Rachel Appel)
Клиентская библиотека JavaScript для ASP.NET Core SignalR позволяет разработчикам вызывать код концентратора на стороне SignalR сервера.
Установка клиентского SignalR пакета
Клиентская SignalR библиотека JavaScript поставляется в виде пакета npm . В следующих разделах описаны различные способы установки клиентской библиотеки.
Установка с помощью npm
Выполните следующие команды из консоли диспетчер пакетов:
npm init -y
npm install @microsoft/signalr
npm устанавливает содержимое пакета в папке node_modules\@microsoft\\signalrdist\browser . Создайте папку wwwroot/lib/signalr . signalr.js
Скопируйте файл в папку wwwroot/lib/signalr.
Ссылка на SignalR клиент JavaScript в элементе <script>
. Например:
<script src="~/lib/signalr/signalr.js"></script>
Использование сеть доставки содержимого (CDN)
Чтобы использовать клиентную библиотеку без предварительных требований npm, наведите ссылку на размещенную в CDN копию клиентской библиотеки. Например:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
Клиентская библиотека доступна на следующих CDN:
Установка с помощью LibMan
LibMan можно использовать для установки определенных файлов клиентской библиотеки из клиентской библиотеки, размещенной в CDN. Например, добавьте в проект только минифицированный файл JavaScript. Дополнительные сведения об этом подходе см. в разделе "Добавление клиентской SignalR библиотеки".
Подключение к концентратору
Следующий код создает и запускает подключение. Имя концентратора является нечувствительным к регистру:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Start the connection.
start();
Подключения между источниками (CORS)
Как правило, браузеры загружают подключения из того же домена, что и запрошенная страница. Однако при подключении к другому домену возникают случаи, когда требуется подключение.
При выполнении запросов между доменами код клиента должен использовать абсолютный URL-адрес вместо относительного URL-адреса. Для запросов между доменами измените значение .withUrl("/chathub")
.withUrl("https://{App domain name}/chathub")
на .
Чтобы предотвратить чтение конфиденциальных данных с другого сайта вредоносным сайтом, по умолчанию подключения между источниками отключены. Чтобы разрешить запрос между источниками, включите CORS:
using SignalRChat.Hubs;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://example.com")
.AllowAnyHeader()
.WithMethods("GET", "POST")
.AllowCredentials();
});
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// UseCors must be called before MapHub.
app.UseCors();
app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
app.Run();
UseCors необходимо вызвать перед вызовом MapHub.
Методы концентратора вызовов от клиента
Клиенты JavaScript вызывают общедоступные методы в центрах с помощью метода вызова HubConnection. Метод invoke
принимает:
- Имя метода концентратора.
- Все аргументы, определенные в методе концентратора.
В следующем выделенном коде имя метода в концентраторе равно SendMessage
. Второй и третий аргументы, передаваемые для invoke
сопоставления с аргументами и message
аргументами концентратораuser
:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Вызов методов концентратора из клиента поддерживается только при использовании службы Azure SignalR в режиме по умолчанию . Дополнительные сведения см. в статье "Часто задаваемые вопросы" (репозиторий Azure-GitHubsignalr).
Метод invoke
возвращает JavaScript Promise
. Разрешение Promise
выполняется с возвращаемым значением (при наличии), когда метод на сервере возвращается. Если метод на сервере выдает ошибку, Promise
он отклоняется с сообщением об ошибке. Используйте async
и методы и then
await
Promise
catch
методы для обработки этих случаев.
Клиенты JavaScript также могут вызывать общедоступные методы в центрах с помощью метода отправкиHubConnection
. invoke
В отличие от метода, send
метод не ожидает ответа от сервера. Метод send
возвращает JavaScript Promise
. Разрешается Promise
при отправке сообщения на сервер. Если сообщение отправляет сообщение об ошибке, Promise
сообщение об ошибке отклоняется. Используйте async
и методы и then
await
Promise
catch
методы для обработки этих случаев.
Использование send
не ожидает, пока сервер не получит сообщение. Следовательно, невозможно вернуть данные или ошибки с сервера.
Вызов клиентских методов из концентратора
Чтобы получать сообщения из концентратора, определите метод с помощью метода .HubConnection
- Имя клиентского метода 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
.
Рекомендуется вызвать метод запуска после HubConnection
on
. Это гарантирует регистрацию обработчиков перед получением сообщений.
Обработка ошибок и ведение журнала
Используется 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
: трассировка сообщений. Регистрирует все данные, включая данные, транспортируемые между концентратором и клиентом.
Используйте метод configureLogging в HubConnectionBuilder, чтобы настроить уровень журнала. Сообщения записываются в консоль браузера:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
Повторное подключение клиентов
Автоматическое повторное подключение
Клиент SignalR JavaScript можно настроить для автоматического повторного подключения с помощью метода WithAutomaticReconnect в HubConnectionBuilder. По умолчанию он не будет автоматически повторно подключаться.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Без параметров WithAutomaticReconnect настраивает клиент ждать 0, 2, 10 и 30 секунд соответственно, прежде чем пытаться повторно подключиться. После четырех неудачных попыток он останавливает попытку повторного подключения.
Перед началом любых попыток повторного подключения :HubConnection
- Переходит в
HubConnectionState.Reconnecting
состояние и запускает обратныеonreconnecting
вызовы. - Не переходит в
Disconnected
состояние и запускает обратныеonclose
вызовы, такие какHubConnection
без автоматического повторного подключения.
Подход повторного подключения предоставляет возможность:
- Предупреждать пользователей о том, что подключение было потеряно.
- Отключить элементы пользовательского интерфейса.
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("messageList").appendChild(li);
});
Если клиент успешно повторно подключается в рамках первых четырех попыток, HubConnection
переход обратно в Connected
состояние и обратный onreconnected
вызов. Это дает возможность сообщить пользователям, что подключение было восстановлено.
Так как подключение выглядит совершенно новым на сервере, connectionId
новое предоставляется обратному вызову onreconnected
.
Параметр onreconnected
обратного вызова connectionId
не определен, если HubConnection
настроено пропустить согласование.
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("messageList").appendChild(li);
});
withAutomaticReconnect
не настраивает повторные HubConnection
начальные сбои запуска, поэтому при выполнении сбоев запуска необходимо обрабатывать вручную:
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("SignalR 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("messageList").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 секунд, которая совпадает с конфигурацией по умолчанию.
Настроенное время повторного подключения отличается от поведения по умолчанию путем остановки после сбоя третьей попытки повторного подключения вместо попытки повторного подключения в течение еще 30 секунд.
Для получения большего контроля над временем и количеством попыток withAutomaticReconnect
автоматического повторного подключения принимает объект, реализующий IRetryPolicy
интерфейс, имеющий один метод с именем nextRetryDelayInMilliseconds
.
nextRetryDelayInMilliseconds
принимает один аргумент с типом RetryContext
. Имеет RetryContext
три свойства: previousRetryCount
elapsedMilliseconds
и retryReason
которые являются number
, number
а также соответственноError
. Перед первой попыткой previousRetryCount
повторного подключения оба и elapsedMilliseconds
будет нулевым, и retryReason
будет ошибка, которая привела к потере подключения. После каждой неудачной попытки previousRetryCount
повторных попыток будет увеличиваться по одному, elapsedMilliseconds
будет обновлено, чтобы отразить время повторного подключения до сих пор в миллисекундах, и retryReason
будет ошибка, которая вызвала последнюю попытку повторного подключения.
nextRetryDelayInMilliseconds
должен возвращать либо число, представляющее число миллисекунда, которое должно ожидаться до следующей попытки повторного подключения, либо 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
функция) создается для запуска подключения. - Вызовите функцию
start
в обработчике событий подключенияonclose
.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
В производственных реализациях обычно используется экспоненциальное обратное или повторное выполнение указанного количества раз.
Вкладка "Спящий браузер"
Некоторые браузеры имеют функцию замораживания или спящего состояния, чтобы уменьшить использование ресурсов компьютера для неактивных вкладок. Это может привести SignalR к закрытию подключений и может привести к нежелательному взаимодействие с пользователем. Браузеры используют эвристики, чтобы выяснить, следует ли поместить вкладку в спящий режим, например:
- Воспроизведение звука
- Хранение веб-блокировки
IndexedDB
Хранение блокировки- Подключение к USB-устройству
- Запись видео или звука
- Зеркальное отображение
- Запись окна или отображения
Эвристики браузера могут меняться со временем и могут отличаться между браузерами. Проверьте матрицу поддержки и узнайте, какой метод лучше всего подходит для ваших сценариев.
Чтобы избежать размещения приложения в спящий режим, приложение должно активировать одну из эвристики, которую использует браузер.
В следующем примере кода показано, как использовать веб-блокировку для поддержания пробуждения вкладки и предотвращения неожиданного закрытия подключения.
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;
});
}
В приведенном выше примере кода:
- Веб-блокировки являются экспериментальными. Условный флажок подтверждает, что браузер поддерживает веб-блокировки.
- Сопоставитель
lockResolver
обещаний хранится таким образом, чтобы блокировка была освобождена, когда она допустима для перехода на вкладку в спящий режим. - При закрытии подключения блокировка освобождается путем вызова
lockResolver()
. При освобождении блокировки вкладка разрешена в спящий режим.
Дополнительные ресурсы
Автор: Рэйчел Аппель (Rachel Appel)
Клиентская библиотека JavaScript для ASP.NET Core SignalR позволяет разработчикам вызывать код концентратора на стороне сервера.
Просмотреть или скачать образец кода (описание загрузки)
Установка клиентского SignalR пакета
Клиентская SignalR библиотека JavaScript поставляется в виде пакета npm . В следующих разделах описаны различные способы установки клиентской библиотеки.
Установка с помощью npm
Для Visual Studio выполните следующие команды из консоли диспетчер пакетов во время работы в корневой папке. Для Visual Studio Code выполните следующие команды из интегрированного терминала.
npm init -y
npm install @microsoft/signalr
npm устанавливает содержимое пакета в папке node_modules\@microsoft\\signalrdist\browser . Создайте новую папку с именем signalr в папке wwwroot\lib . Скопируйте файл в signalr.js
папку wwwroot\lib\signalr .
Ссылка на SignalR клиент JavaScript в элементе <script>
. Например:
<script src="~/lib/signalr/signalr.js"></script>
Использование сеть доставки содержимого (CDN)
Чтобы использовать клиентную библиотеку без предварительных требований npm, наведите ссылку на размещенную в CDN копию клиентской библиотеки. Например:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.js"></script>
Клиентская библиотека доступна на следующих CDN:
Установка с помощью LibMan
LibMan можно использовать для установки определенных файлов клиентской библиотеки из клиентской библиотеки, размещенной в CDN. Например, добавьте в проект только минифицированный файл JavaScript. Дополнительные сведения об этом подходе см. в разделе "Добавление клиентской SignalR библиотеки".
Подключение к концентратору
Следующий код создает и запускает подключение. Имя концентратора является нечувствительным к регистру:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Start the connection.
start();
Подключения между источниками
Как правило, браузеры загружают подключения из того же домена, что и запрошенная страница. Однако при подключении к другому домену возникают случаи, когда требуется подключение.
Внимание
Клиентский код должен использовать абсолютный URL-адрес вместо относительного URL-адреса. Измените .withUrl("/chathub")
на .withUrl("https://myappurl/chathub")
.
Чтобы предотвратить чтение конфиденциальных данных с другого сайта вредоносным сайтом, по умолчанию подключения между источниками отключены. Чтобы разрешить запрос между источниками Startup
, включите его в классе:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SignalRChat.Hubs;
namespace SignalRChat
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR();
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("https://example.com")
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<ChatHub>("/chathub");
});
}
}
}
Методы концентратора вызовов от клиента
Клиенты JavaScript вызывают общедоступные методы в центрах с помощью метода вызова HubConnection. Метод invoke
принимает:
- Имя метода концентратора.
- Все аргументы, определенные в методе концентратора.
В следующем примере имя метода в концентраторе равно SendMessage
. Второй и третий аргументы, передаваемые для invoke
сопоставления с аргументами и message
аргументами концентратораuser
:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Примечание.
Вызов методов концентратора из клиента поддерживается только при использовании службы Azure SignalR в режиме по умолчанию . Дополнительные сведения см. в статье "Часто задаваемые вопросы" (репозиторий Azure-GitHubsignalr).
Метод invoke
возвращает JavaScript Promise
. Разрешение Promise
выполняется с возвращаемым значением (при наличии), когда метод на сервере возвращается. Если метод на сервере выдает ошибку, Promise
он отклоняется с сообщением об ошибке. Используйте async
и методы и then
await
Promise
catch
методы для обработки этих случаев.
Клиенты JavaScript также могут вызывать общедоступные методы в центрах с помощью метода отправкиHubConnection
. invoke
В отличие от метода, send
метод не ожидает ответа от сервера. Метод send
возвращает JavaScript Promise
. Разрешается Promise
при отправке сообщения на сервер. Если сообщение отправляет сообщение об ошибке, Promise
сообщение об ошибке отклоняется. Используйте async
и методы и then
await
Promise
catch
методы для обработки этих случаев.
Примечание.
Использование send
не ожидает, пока сервер не получит сообщение. Следовательно, невозможно вернуть данные или ошибки с сервера.
Вызов клиентских методов из концентратора
Чтобы получать сообщения из концентратора, определите метод с помощью метода .HubConnection
- Имя клиентского метода 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 сервера с помощью метода:
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
SignalR определяет, какой метод клиента следует вызывать путем сопоставления имени метода и аргументов, определенных в SendAsync
и connection.on
.
Примечание.
В качестве оптимальной практики вызовите метод start в послеon
HubConnection
. Это гарантирует регистрацию обработчиков перед получением сообщений.
Обработка ошибок и ведение журнала
Используйте и с методом или catch
await
Promise
методом для обработки ошибок на стороне клиента.async
catch
try
Используется 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
: трассировка сообщений. Регистрирует все данные, включая данные, транспортируемые между концентратором и клиентом.
Используйте метод configureLogging в HubConnectionBuilder, чтобы настроить уровень журнала. Сообщения записываются в консоль браузера:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
Повторное подключение клиентов
Автоматическое повторное подключение
Клиент SignalR JavaScript можно настроить для автоматического withAutomaticReconnect
повторного подключения с помощью метода в HubConnectionBuilder. По умолчанию он не будет автоматически повторно подключаться.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Без параметров withAutomaticReconnect()
клиент настраивает ожидание 0, 2, 10 и 30 секунд соответственно, прежде чем пытаться выполнить каждую попытку повторного подключения, остановившись после четырех неудачных попыток.
Перед началом любых попыток HubConnection
повторного подключения он перейдет в HubConnectionState.Reconnecting
состояние и запускает обратные onreconnecting
вызовы вместо перехода к Disconnected
состоянию и активации обратных onclose
вызовов, таких как HubConnection
без автоматического повторного подключения. Это дает возможность предупредить пользователей о том, что подключение потеряно и отключает элементы пользовательского интерфейса.
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("messageList").appendChild(li);
});
Если клиент успешно повторно подключается в течение первых четырех попыток, HubConnection
он вернется к Connected
состоянию и вызовет обратный onreconnected
вызов. Это дает возможность сообщить пользователям, что подключение было восстановлено.
Так как подключение выглядит совершенно новым на сервере, новое connectionId
будет предоставлено обратному вызову onreconnected
.
Предупреждение
Параметр onreconnected
обратного вызова connectionId
не определен, если HubConnection
настроено пропустить согласование.
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("messageList").appendChild(li);
});
withAutomaticReconnect()
не настраивает повторные HubConnection
начальные сбои запуска, поэтому при выполнении сбоев запуска необходимо обрабатывать вручную:
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("SignalR 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("messageList").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 секунд, которая снова похожа на конфигурацию по умолчанию.
Затем настраиваемое поведение снова расходится от поведения по умолчанию, остановив после третьей попытки повторного подключения, вместо того, чтобы попробовать еще одну попытку повторного подключения в еще 30 секунд, как это было бы в конфигурации по умолчанию.
Если требуется еще больше контроля над временем и количеством попыток автоматического повторного подключения, withAutomaticReconnect
принимает объект, реализующий IRetryPolicy
интерфейс, имеющий один метод с именем nextRetryDelayInMilliseconds
.
nextRetryDelayInMilliseconds
принимает один аргумент с типом RetryContext
. Имеет RetryContext
три свойства: previousRetryCount
elapsedMilliseconds
и retryReason
которые являются number
, number
а также соответственноError
. Перед первой попыткой previousRetryCount
повторного подключения оба и elapsedMilliseconds
будет нулевым, и retryReason
будет ошибка, которая привела к потере подключения. После каждой неудачной попытки previousRetryCount
повторных попыток будет увеличиваться по одному, elapsedMilliseconds
будет обновлено, чтобы отразить время повторного подключения до сих пор в миллисекундах, и retryReason
будет ошибка, которая вызвала последнюю попытку повторного подключения.
nextRetryDelayInMilliseconds
должен возвращать либо число, представляющее число миллисекунда, которое должно ожидаться до следующей попытки повторного подключения, либо 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
функция) создается для запуска подключения. - Вызовите функцию
start
в обработчике событий подключенияonclose
.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
В производственных реализациях обычно используется экспоненциальное обратное или повторное выполнение указанного количества раз.
Вкладка "Спящий браузер"
Некоторые браузеры имеют функцию замораживания или спящего состояния, чтобы уменьшить использование ресурсов компьютера для неактивных вкладок. Это может привести SignalR к закрытию подключений и может привести к нежелательному взаимодействие с пользователем. Браузеры используют эвристики, чтобы выяснить, следует ли поместить вкладку в спящий режим, например:
- Воспроизведение звука
- Хранение веб-блокировки
IndexedDB
Хранение блокировки- Подключение к USB-устройству
- Запись видео или звука
- Зеркальное отображение
- Запись окна или отображения
Примечание.
Эти эвристики могут меняться со временем или отличаться между браузерами. Проверьте матрицу поддержки и узнайте, какой метод лучше всего подходит для ваших сценариев.
Чтобы избежать размещения приложения в спящий режим, приложение должно активировать одну из эвристики, которую использует браузер.
В следующем примере кода показано, как использовать веб-блокировку для поддержания пробуждения вкладки и предотвращения неожиданного закрытия подключения.
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;
});
}
В приведенном выше примере кода:
- Веб-блокировки являются экспериментальными. Условный флажок подтверждает, что браузер поддерживает веб-блокировки.
- Сопоставитель обещаний (
lockResolver
) хранится таким образом, чтобы блокировка была освобождена, когда она допустима для перехода на вкладку в спящий режим. - При закрытии подключения блокировка освобождается путем вызова
lockResolver()
. При освобождении блокировки вкладка разрешена в спящий режим.
Дополнительные ресурсы
ASP.NET Core