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 . Misalnya:

<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. Misalnya:

<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.

Koneksi 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 pemanggilanHub Koneksi ion. 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 (repositori GitHub azure-signalr).

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 Promisemetode then dan catch untuk menangani kasus ini.

Klien JavaScript juga dapat memanggil metode publik di hub melalui metode HubConnectionpengiriman . Tidak seperti metode , invokesend 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 Promisemetode then dan catch untuk menangani kasus ini.

Penggunaan sendtidak 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 mencatat Error pesan.
  • signalR.LogLevel.Warning: Pesan peringatan tentang potensi kesalahan. WarningLog , dan Error pesan.
  • signalR.LogLevel.Information: Pesan status tanpa kesalahan. InformationLog , Warning, dan Error pesan.
  • signalR.LogLevel.Trace: Lacak pesan. Mencatat semuanya, termasuk data yang diangkut antara hub dan klien.

Gunakan metode configureLogging di Hub Koneksi ionBuilder 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 Hub Koneksi ionBuilder. 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 baliknya onreconnecting .
  • Tidak beralih ke Disconnected status dan memicu panggilan baliknya onclose seperti HubConnection 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 connectionIdtidak 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 previousRetryCountelapsedMilliseconds 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:

  1. Fungsi (dalam hal ini, start fungsi) dibuat untuk memulai koneksi.
  2. 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 . Misalnya:

<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. Misalnya:

<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.

Koneksi 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 pemanggilanHub Koneksi ion. 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 (repositori GitHub azure-signalr).

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 Promisemetode then dan catch untuk menangani kasus ini.

Klien JavaScript juga dapat memanggil metode publik di hub melalui metode HubConnectionpengiriman . Tidak seperti metode , invokesend 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 Promisemetode 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 Promisemetode 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 mencatat Error pesan.
  • signalR.LogLevel.Warning: Pesan peringatan tentang potensi kesalahan. WarningLog , dan Error pesan.
  • signalR.LogLevel.Information: Pesan status tanpa kesalahan. InformationLog , Warning, dan Error pesan.
  • signalR.LogLevel.Trace: Lacak pesan. Mencatat semuanya, termasuk data yang diangkut antara hub dan klien.

Gunakan metode configureLogging di Hub Koneksi ionBuilder 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 Hub Koneksi ionBuilder. 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 previousRetryCountelapsedMilliseconds 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:

  1. Fungsi (dalam hal ini, start fungsi) dibuat untuk memulai koneksi.
  2. 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