klien ASP.NET Core SignalR JavaScript
Oleh Rachel Appel
Pustaka klien ASP.NET Core SignalR JavaScript memungkinkan pengembang untuk memanggil kode hub sisi SignalR server.
SignalR Menginstal paket klien
SignalR Pustaka klien JavaScript dikirimkan sebagai paket npm. Bagian berikut menguraikan berbagai cara untuk menginstal pustaka klien.
Menginstal dengan npm
Jalankan perintah berikut dari Package Manager Console:
npm init -y
npm install @microsoft/signalr
npm menginstal konten paket di folder node_modules\@microsoft\signalr\dist\browser . Buat folder wwwroot/lib/signalr . signalr.js
Salin file ke folder wwwroot/lib/signalr.
Referensikan SignalR klien JavaScript dalam <script>
elemen . Contohnya:
<script src="~/lib/signalr/signalr.js"></script>
Menggunakan Content Delivery Network (CDN)
Untuk menggunakan pustaka klien tanpa prasyarat npm, referensikan salinan pustaka klien yang dihosting CDN. Contohnya:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
Pustaka klien tersedia pada CDN berikut:
Menginstal dengan LibMan
LibMan dapat digunakan untuk menginstal file pustaka klien tertentu dari pustaka klien yang dihosting CDN. Misalnya, hanya tambahkan file JavaScript yang dikurangi ke proyek. Untuk detail tentang pendekatan tersebutSignalR, lihat Menambahkan pustaka klien.
Menyambungkan ke hub
Kode berikut membuat dan memulai koneksi. Nama hub tidak peka huruf besar/kecil:
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();
Koneksi lintas asal (CORS)
Biasanya, browser memuat koneksi dari domain yang sama dengan halaman yang diminta. Namun, ada kalanya koneksi ke domain lain diperlukan.
Saat membuat permintaan lintas domain, kode klien harus menggunakan URL absolut alih-alih URL relatif. Untuk permintaan lintas domain, ubah .withUrl("/chathub")
ke .withUrl("https://{App domain name}/chathub")
.
Untuk mencegah situs berbahaya membaca data sensitif dari situs lain, koneksi lintas asal dinonaktifkan secara default. Untuk mengizinkan permintaan lintas asal, aktifkan 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 harus dipanggil sebelum memanggil MapHub.
Metode hub panggilan dari klien
Klien JavaScript memanggil metode publik di hub melalui metode pemanggilan HubConnection. Metode ini invoke
menerima:
- Nama metode hub.
- Argumen apa pun yang ditentukan dalam metode hub.
Dalam kode yang disorot berikut, nama metode pada hub adalah SendMessage
. Argumen kedua dan ketiga yang diteruskan untuk invoke
memetakan ke metode user
hub dan message
argumen:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Metode hub panggilan dari klien hanya didukung saat menggunakan Layanan Azure SignalR dalam mode Default . Untuk informasi selengkapnya, lihat Tanya Jawab Umum (azure-signalr repositori GitHub).
Metode invoke
mengembalikan JavaScript Promise
. Promise
diselesaikan dengan nilai pengembalian (jika ada) ketika metode pada server kembali. Jika metode di server melemparkan kesalahan, ditolak Promise
dengan pesan kesalahan. Gunakan async
dan await
atau Promise
metode then
dan catch
untuk menangani kasus ini.
Klien JavaScript juga dapat memanggil metode publik di hub melalui metode HubConnection
pengiriman . Tidak seperti metode , invoke
send
metode tidak menunggu respons dari server. Metode send
mengembalikan JavaScript Promise
. Promise
diselesaikan ketika pesan telah dikirim ke server. Jika ada kesalahan saat mengirim pesan, pesan Promise
ditolak dengan kesalahan. Gunakan async
dan await
atau Promise
metode then
dan catch
untuk menangani kasus ini.
Penggunaan send
tidak menunggu hingga server menerima pesan. Akibatnya, tidak dimungkinkan untuk mengembalikan data atau kesalahan dari server.
Memanggil metode klien dari hub
Untuk menerima pesan dari hub, tentukan metode menggunakan metode on dari HubConnection
.
- Nama metode klien JavaScript.
- Argumen yang diteruskan hub ke metode .
Dalam contoh berikut, nama metodenya adalah ReceiveMessage
. Nama argumen adalah user
dan message
:
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messageList").appendChild(li);
});
Kode sebelumnya dalam connection.on
berjalan ketika kode sisi server memanggilnya menggunakan SendAsync metode :
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 menentukan metode klien mana yang akan dipanggil dengan mencocokkan nama metode dan argumen yang ditentukan dalam SendAsync
dan connection.on
.
Praktik terbaik adalah memanggil metode mulai pada HubConnection
setelah on
. Melakukannya memastikan handler terdaftar sebelum pesan diterima.
Penanganan kesalahan dan pengelogan
Gunakan console.error
untuk menghasilkan kesalahan ke konsol browser saat klien tidak dapat menyambungkan atau mengirim pesan:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Siapkan pelacakan log sisi klien dengan meneruskan pencatat dan jenis peristiwa untuk mencatat saat koneksi dibuat. Pesan dicatat dengan tingkat log yang ditentukan dan yang lebih tinggi. Tingkat log yang tersedia adalah sebagai berikut:
signalR.LogLevel.Error
: Pesan kesalahan. Hanya mencatatError
pesan.signalR.LogLevel.Warning
: Pesan peringatan tentang potensi kesalahan.Warning
Log , danError
pesan.signalR.LogLevel.Information
: Pesan status tanpa kesalahan.Information
Log ,Warning
, danError
pesan.signalR.LogLevel.Trace
: Lacak pesan. Mencatat semuanya, termasuk data yang diangkut antara hub dan klien.
Gunakan metode configureLogging di HubConnectionBuilder untuk mengonfigurasi tingkat log. Pesan dicatat ke konsol browser:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
Menyambungkan kembali klien
Menyambungkan ulang secara otomatis
Klien JavaScript untuk SignalR dapat dikonfigurasi untuk terhubung kembali secara otomatis menggunakan metode WithAutomaticReconnect di HubConnectionBuilder. Ini tidak akan secara otomatis terhubung kembali secara default.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Tanpa parameter apa pun, WithAutomaticReconnect mengonfigurasi klien untuk masing-masing menunggu 0, 2, 10, dan 30 detik sebelum mencoba setiap upaya koneksi ulang. Setelah empat upaya gagal, ia berhenti mencoba menyambungkan kembali.
Sebelum memulai upaya koneksi ulang, :HubConnection
- Transisi ke
HubConnectionState.Reconnecting
status dan mengaktifkan panggilan baliknyaonreconnecting
. - Tidak beralih ke
Disconnected
status dan memicu panggilan baliknyaonclose
sepertiHubConnection
tanpa koneksi ulang otomatis dikonfigurasi.
Pendekatan reconnect memberikan kesempatan untuk:
- Peringatkan pengguna bahwa koneksi telah hilang.
- Nonaktifkan elemen 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("messageList").appendChild(li);
});
Jika klien berhasil terhubung kembali dalam empat upaya pertamanya, HubConnection
transisi kembali ke Connected
status dan mengaktifkan panggilan baliknya onreconnected
. Ini memberikan kesempatan untuk memberi tahu pengguna bahwa koneksi telah diterbitkan kembali.
Karena koneksi terlihat sama sekali baru ke server, baru connectionId
disediakan untuk onreconnected
panggilan balik.
Parameter onreconnected
panggilan balik connectionId
tidak ditentukan jika dikonfigurasi HubConnection
untuk melewati negosiasi.
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
tidak akan mengonfigurasi HubConnection
untuk mencoba kembali kegagalan awal, jadi kegagalan mulai perlu ditangani secara manual:
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);
}
};
Jika klien tidak berhasil menyambungkan kembali dalam empat upaya pertamanya, transisi ke Disconnected
status dan mengaktifkan panggilan balik onklosenya.HubConnection
Ini memberikan kesempatan untuk memberi tahu pengguna:
- Sambungan telah hilang secara permanen.
- Coba refresh halaman:
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);
});
Untuk mengonfigurasi jumlah kustom upaya koneksi ulang sebelum memutuskan atau mengubah waktu koneksi ulang, withAutomaticReconnect
menerima array angka yang mewakili penundaan dalam milidetik untuk menunggu sebelum memulai setiap upaya koneksi ulang.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
Contoh sebelumnya mengonfigurasi HubConnection
untuk mulai mencoba menyambungkan kembali segera setelah koneksi hilang. Konfigurasi default juga menunggu nol detik untuk mencoba menyambungkan kembali.
Jika upaya koneksi ulang pertama gagal, upaya koneksi ulang kedua juga segera dimulai alih-alih menunggu 2 detik menggunakan konfigurasi default.
Jika upaya koneksi ulang kedua gagal, upaya koneksi ulang ketiga dimulai dalam 10 detik yang sama dengan konfigurasi default.
Waktu koneksi ulang yang dikonfigurasi berbeda dari perilaku default dengan berhenti setelah kegagalan upaya koneksi ulang ketiga alih-alih mencoba satu lagi upaya koneksi ulang dalam 30 detik lagi.
Untuk kontrol lebih besar atas waktu dan jumlah upaya koneksi ulang otomatis, withAutomaticReconnect
menerima objek yang mengimplementasikan IRetryPolicy
antarmuka, yang memiliki satu metode bernama nextRetryDelayInMilliseconds
.
nextRetryDelayInMilliseconds
mengambil satu argumen dengan jenis RetryContext
. memiliki RetryContext
tiga properti: previousRetryCount
, elapsedMilliseconds
dan retryReason
yang masing-masing adalah number
, a number
dan Error
. Sebelum upaya koneksi ulang pertama, dan previousRetryCount
elapsedMilliseconds
akan menjadi nol, dan retryReason
akan menjadi Kesalahan yang menyebabkan koneksi hilang. Setelah setiap upaya coba lagi yang gagal, previousRetryCount
akan bertambah satu, elapsedMilliseconds
akan diperbarui untuk mencerminkan jumlah waktu yang dihabiskan untuk menyambungkan kembali sejauh ini dalam milidetik, dan retryReason
akan menjadi Kesalahan yang menyebabkan upaya koneksi ulang terakhir gagal.
nextRetryDelayInMilliseconds
harus mengembalikan angka yang menunjukkan jumlah milidetik untuk menunggu sebelum upaya koneksi ulang berikutnya atau null
jika HubConnection
harus berhenti menyambungkan kembali.
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();
Atau, kode dapat ditulis yang menghubungkan kembali klien secara manual seperti yang ditunjukkan di bagian berikut.
Menyambungkan ulang secara manual
Kode berikut menunjukkan pendekatan koneksi ulang manual yang khas:
- Fungsi (dalam hal ini,
start
fungsi) dibuat untuk memulai koneksi. start
Panggil fungsi di penanganan aktivitas koneksionclose
.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
Implementasi produksi biasanya menggunakan back-off eksponensial atau mencoba kembali beberapa kali yang ditentukan.
Tab tidur browser
Beberapa browser memiliki fitur pembeku tab atau tidur untuk mengurangi penggunaan sumber daya komputer untuk tab yang tidak aktif. Ini dapat menyebabkan SignalR koneksi ditutup dan dapat mengakibatkan pengalaman pengguna yang tidak diinginkan. Browser menggunakan heuristik untuk mencari tahu apakah tab harus ditidur, seperti:
- Memutar audio
- Menahan kunci web
- Menahan
IndexedDB
kunci - Tersambung ke perangkat USB
- Menangkap video atau audio
- Sedang dicerminkan
- Menangkap jendela atau tampilan
Heuristik browser dapat berubah dari waktu ke waktu dan dapat berbeda di antara browser. Periksa matriks dukungan dan cari tahu metode apa yang paling sesuai untuk skenario Anda.
Untuk menghindari tidurnya aplikasi, aplikasi harus memicu salah satu heuristik yang digunakan browser.
Contoh kode berikut menunjukkan cara menggunakan Kunci Web untuk menjaga tab tetap terjaga dan menghindari penutupan koneksi yang tidak terduga.
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;
});
}
Untuk contoh kode sebelumnya:
- Kunci Web bersifat eksperimental. Pemeriksaan kondisional mengonfirmasi bahwa browser mendukung Kunci Web.
- Pemecah janji,
lockResolver
, disimpan sehingga kunci dapat dilepaskan ketika dapat diterima agar tab tidur. - Saat menutup koneksi, kunci dilepaskan dengan memanggil
lockResolver()
. Saat kunci dilepaskan, tab diizinkan untuk tidur.
Sumber Daya Tambahan:
Oleh Rachel Appel
Pustaka klien ASP.NET Core SignalR JavaScript memungkinkan pengembang untuk memanggil kode hub sisi server.
Melihat atau mengunduh kode sampel (cara mengunduh)
SignalR Menginstal paket klien
SignalR Pustaka klien JavaScript dikirimkan sebagai paket npm. Bagian berikut menguraikan berbagai cara untuk menginstal pustaka klien.
Menginstal dengan npm
Untuk Visual Studio, jalankan perintah berikut dari Package Manager Console saat berada di folder akar. Untuk Visual Studio Code, jalankan perintah berikut dari Terminal Terintegrasi.
npm init -y
npm install @microsoft/signalr
npm menginstal konten paket di folder node_modules\@microsoft\signalr\dist\browser . Buat folder baru bernama signalr di bawah folder wwwroot\lib . signalr.js
Salin file ke folder wwwroot\lib\signalr.
Referensikan SignalR klien JavaScript dalam <script>
elemen . Contohnya:
<script src="~/lib/signalr/signalr.js"></script>
Menggunakan Content Delivery Network (CDN)
Untuk menggunakan pustaka klien tanpa prasyarat npm, referensikan salinan pustaka klien yang dihosting CDN. Contohnya:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.js"></script>
Pustaka klien tersedia pada CDN berikut:
Menginstal dengan LibMan
LibMan dapat digunakan untuk menginstal file pustaka klien tertentu dari pustaka klien yang dihosting CDN. Misalnya, hanya tambahkan file JavaScript yang dikurangi ke proyek. Untuk detail tentang pendekatan tersebutSignalR, lihat Menambahkan pustaka klien.
Menyambungkan ke hub
Kode berikut membuat dan memulai koneksi. Nama hub tidak peka huruf besar/kecil:
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();
Koneksi lintas asal
Biasanya, browser memuat koneksi dari domain yang sama dengan halaman yang diminta. Namun, ada kalanya koneksi ke domain lain diperlukan.
Penting
Kode klien harus menggunakan URL absolut alih-alih URL relatif. Ubah .withUrl("/chathub")
ke .withUrl("https://myappurl/chathub")
.
Untuk mencegah situs berbahaya membaca data sensitif dari situs lain, koneksi lintas asal dinonaktifkan secara default. Untuk mengizinkan permintaan lintas asal, aktifkan di Startup
kelas :
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");
});
}
}
}
Metode hub panggilan dari klien
Klien JavaScript memanggil metode publik di hub melalui metode pemanggilan HubConnection. Metode ini invoke
menerima:
- Nama metode hub.
- Argumen apa pun yang ditentukan dalam metode hub.
Dalam contoh berikut, nama metode pada hub adalah SendMessage
. Argumen kedua dan ketiga yang diteruskan untuk invoke
memetakan ke metode user
hub dan message
argumen:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Catatan
Metode hub panggilan dari klien hanya didukung saat menggunakan Layanan Azure SignalR dalam mode Default . Untuk informasi selengkapnya, lihat Tanya Jawab Umum (azure-signalr repositori GitHub).
Metode invoke
mengembalikan JavaScript Promise
. Promise
diselesaikan dengan nilai pengembalian (jika ada) ketika metode pada server kembali. Jika metode di server melemparkan kesalahan, ditolak Promise
dengan pesan kesalahan. Gunakan async
dan await
atau Promise
metode then
dan catch
untuk menangani kasus ini.
Klien JavaScript juga dapat memanggil metode publik di hub melalui metode HubConnection
pengiriman . Tidak seperti metode , invoke
send
metode tidak menunggu respons dari server. Metode send
mengembalikan JavaScript Promise
. Promise
diselesaikan ketika pesan telah dikirim ke server. Jika ada kesalahan saat mengirim pesan, pesan Promise
ditolak dengan kesalahan. Gunakan async
dan await
atau Promise
metode then
dan catch
untuk menangani kasus ini.
Catatan
Penggunaan send
tidak menunggu hingga server menerima pesan. Akibatnya, tidak dimungkinkan untuk mengembalikan data atau kesalahan dari server.
Memanggil metode klien dari hub
Untuk menerima pesan dari hub, tentukan metode menggunakan metode on dari HubConnection
.
- Nama metode klien JavaScript.
- Argumen yang diteruskan hub ke metode .
Dalam contoh berikut, nama metodenya adalah ReceiveMessage
. Nama argumen adalah user
dan message
:
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messageList").appendChild(li);
});
Kode sebelumnya dalam connection.on
berjalan ketika kode sisi server memanggilnya menggunakan SendAsync metode :
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
SignalR menentukan metode klien mana yang akan dipanggil dengan mencocokkan nama metode dan argumen yang ditentukan dalam SendAsync
dan connection.on
.
Catatan
Sebagai praktik terbaik, panggil metode mulai pada HubConnection
setelah on
. Melakukannya memastikan handler Anda terdaftar sebelum pesan diterima.
Penanganan kesalahan dan pengelogan
Gunakan try
dan catch
dengan async
dan await
atau Promise
metode untuk catch
menangani kesalahan sisi klien. Gunakan console.error
untuk menghasilkan kesalahan ke konsol browser:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Siapkan pelacakan log sisi klien dengan meneruskan pencatat dan jenis peristiwa untuk mencatat saat koneksi dibuat. Pesan dicatat dengan tingkat log yang ditentukan dan yang lebih tinggi. Tingkat log yang tersedia adalah sebagai berikut:
signalR.LogLevel.Error
: Pesan kesalahan. Hanya mencatatError
pesan.signalR.LogLevel.Warning
: Pesan peringatan tentang potensi kesalahan.Warning
Log , danError
pesan.signalR.LogLevel.Information
: Pesan status tanpa kesalahan.Information
Log ,Warning
, danError
pesan.signalR.LogLevel.Trace
: Lacak pesan. Mencatat semuanya, termasuk data yang diangkut antara hub dan klien.
Gunakan metode configureLogging di HubConnectionBuilder untuk mengonfigurasi tingkat log. Pesan dicatat ke konsol browser:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
Menyambungkan kembali klien
Menyambungkan ulang secara otomatis
Klien JavaScript untuk SignalR dapat dikonfigurasi untuk terhubung kembali secara otomatis menggunakan withAutomaticReconnect
metode di HubConnectionBuilder. Ini tidak akan secara otomatis terhubung kembali secara default.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Tanpa parameter apa pun, withAutomaticReconnect()
mengonfigurasi klien untuk menunggu masing-masing 0, 2, 10, dan 30 detik sebelum mencoba setiap upaya koneksi ulang, berhenti setelah empat upaya yang gagal.
Sebelum memulai upaya koneksi ulang, HubConnection
akan beralih ke HubConnectionState.Reconnecting
status dan mengaktifkan panggilan baliknya onreconnecting
alih-alih bertransisi ke Disconnected
status dan memicu panggilan baliknya onclose
seperti HubConnection
tanpa koneksi ulang otomatis dikonfigurasi. Ini memberikan kesempatan untuk memperingatkan pengguna bahwa koneksi telah hilang dan untuk menonaktifkan elemen 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("messageList").appendChild(li);
});
Jika klien berhasil terhubung kembali dalam empat upaya pertamanya, HubConnection
akan transisi kembali ke Connected
status dan mengaktifkan panggilan baliknya onreconnected
. Ini memberikan kesempatan untuk memberi tahu pengguna bahwa koneksi telah diterbitkan kembali.
Karena koneksi terlihat sama sekali baru ke server, baru connectionId
akan disediakan untuk onreconnected
panggilan balik.
Peringatan
Parameter onreconnected
panggilan balik connectionId
tidak akan ditentukan jika HubConnection
dikonfigurasi untuk melewati negosiasi.
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()
tidak akan mengonfigurasi HubConnection
untuk mencoba kembali kegagalan awal, jadi kegagalan mulai perlu ditangani secara manual:
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);
}
};
Jika klien tidak berhasil menyambungkan kembali dalam empat upaya pertamanya, HubConnection
akan beralih ke Disconnected
status dan mengaktifkan panggilan balik onklosenya. Ini memberikan kesempatan untuk memberi tahu pengguna bahwa koneksi telah hilang secara permanen dan merekomendasikan penyegaran halaman:
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);
});
Untuk mengonfigurasi jumlah kustom upaya koneksi ulang sebelum memutuskan atau mengubah waktu koneksi ulang, withAutomaticReconnect
menerima array angka yang mewakili penundaan dalam milidetik untuk menunggu sebelum memulai setiap upaya koneksi ulang.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
Contoh sebelumnya mengonfigurasi HubConnection
untuk mulai mencoba menyambungkan kembali segera setelah koneksi hilang. Ini juga berlaku untuk konfigurasi default.
Jika upaya koneksi ulang pertama gagal, upaya koneksi ulang kedua juga akan segera dimulai alih-alih menunggu 2 detik seperti dalam konfigurasi default.
Jika upaya koneksi ulang kedua gagal, upaya koneksi ulang ketiga akan dimulai dalam 10 detik yang lagi seperti konfigurasi default.
Perilaku kustom kemudian menyimpang lagi dari perilaku default dengan berhenti setelah kegagalan upaya koneksi ulang ketiga alih-alih mencoba satu lagi upaya koneksi ulang dalam 30 detik lain seperti dalam konfigurasi default.
Jika Anda ingin kontrol yang lebih besar atas waktu dan jumlah upaya koneksi ulang otomatis, withAutomaticReconnect
menerima objek yang mengimplementasikan IRetryPolicy
antarmuka, yang memiliki satu metode bernama nextRetryDelayInMilliseconds
.
nextRetryDelayInMilliseconds
mengambil satu argumen dengan jenis RetryContext
. memiliki RetryContext
tiga properti: previousRetryCount
, elapsedMilliseconds
dan retryReason
yang masing-masing adalah number
, a number
dan Error
. Sebelum upaya koneksi ulang pertama, dan previousRetryCount
elapsedMilliseconds
akan menjadi nol, dan retryReason
akan menjadi Kesalahan yang menyebabkan koneksi hilang. Setelah setiap upaya coba lagi yang gagal, previousRetryCount
akan bertambah satu, elapsedMilliseconds
akan diperbarui untuk mencerminkan jumlah waktu yang dihabiskan untuk menyambungkan kembali sejauh ini dalam milidetik, dan retryReason
akan menjadi Kesalahan yang menyebabkan upaya koneksi ulang terakhir gagal.
nextRetryDelayInMilliseconds
harus mengembalikan angka yang menunjukkan jumlah milidetik untuk menunggu sebelum upaya koneksi ulang berikutnya atau null
jika HubConnection
harus berhenti menyambungkan kembali.
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();
Atau, Anda dapat menulis kode yang akan menghubungkan kembali klien Anda secara manual seperti yang ditunjukkan dalam Sambungkan kembali secara manual.
Menyambungkan ulang secara manual
Kode berikut menunjukkan pendekatan koneksi ulang manual yang khas:
- Fungsi (dalam hal ini,
start
fungsi) dibuat untuk memulai koneksi. start
Panggil fungsi di penanganan aktivitas koneksionclose
.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
Implementasi produksi biasanya menggunakan back-off eksponensial atau mencoba kembali beberapa kali yang ditentukan.
Tab tidur browser
Beberapa browser memiliki fitur pembeku tab atau tidur untuk mengurangi penggunaan sumber daya komputer untuk tab yang tidak aktif. Ini dapat menyebabkan SignalR koneksi ditutup dan dapat mengakibatkan pengalaman pengguna yang tidak diinginkan. Browser menggunakan heuristik untuk mencari tahu apakah tab harus ditidur, seperti:
- Memutar audio
- Menahan kunci web
- Menahan
IndexedDB
kunci - Tersambung ke perangkat USB
- Menangkap video atau audio
- Sedang dicerminkan
- Menangkap jendela atau tampilan
Catatan
Heuristik ini dapat berubah dari waktu ke waktu atau berbeda antara browser. Periksa matriks dukungan Anda dan cari tahu metode apa yang paling sesuai untuk skenario Anda.
Untuk menghindari tidurnya aplikasi, aplikasi harus memicu salah satu heuristik yang digunakan browser.
Contoh kode berikut menunjukkan cara menggunakan Kunci Web untuk menjaga tab tetap terjaga dan menghindari penutupan koneksi yang tidak terduga.
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;
});
}
Untuk contoh kode sebelumnya:
- Kunci Web bersifat eksperimental. Pemeriksaan kondisional mengonfirmasi bahwa browser mendukung Kunci Web.
- Pemecah janji (
lockResolver
) disimpan sehingga kunci dapat dilepaskan saat dapat diterima agar tab tidur. - Saat menutup koneksi, kunci dilepaskan dengan memanggil
lockResolver()
. Saat kunci dilepaskan, tab diizinkan untuk tidur.
Sumber Daya Tambahan:
ASP.NET Core