Sdílet prostřednictvím


ASP.NET Core SignalR JavaScript client

Autor: Rachel Appel

Klientská knihovna ASP.NET Core SignalR JavaScript umožňuje vývojářům volat kód centra na straně SignalR serveru.

SignalR Instalace balíčku klienta

Klientská SignalR knihovna JavaScriptu se doručí jako balíček npm . Následující části popisují různé způsoby instalace klientské knihovny.

Instalace pomocí npm

Z konzoly Správce balíčků spusťte následující příkazy:

npm init -y
npm install @microsoft/signalr

npm nainstaluje obsah balíčku do složky node_modules\@microsoft\signalr\dist\browser . Vytvořte složku wwwroot/lib/signalr. signalr.js Zkopírujte soubor do složky wwwroot/lib/signalr.

Odkazovat na javascriptového SignalR klienta v elementu <script> . Příklad:

<script src="~/lib/signalr/signalr.js"></script>

Použití sítě pro doručování obsahu (CDN)

Chcete-li použít klientskou knihovnu bez předpokladu npm, odkazujte na kopii klientské knihovny hostované v CDN. Příklad:

<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>

Klientská knihovna je k dispozici v následujících sítích CDN:

Instalace pomocí nástroje LibMan

Knihovnu LibMan lze použít k instalaci konkrétních souborů klientské knihovny z klientské knihovny hostované v CDN. Například do projektu přidejte pouze minifikovaný javascriptový soubor. Podrobnosti o tomto přístupu najdete v SignalR tématu Přidání klientské knihovny.

Připojení k centru

Následující kód vytvoří a spustí připojení. Název centra nerozlišuje velká a malá písmena:

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();

Připojení mezi zdroji (CORS)

Prohlížeče obvykle načítají připojení ze stejné domény jako požadovaná stránka. Existují však situace, kdy se vyžaduje připojení k jiné doméně.

Při provádění požadavků mezi doménou musí kód klienta místo relativní adresy URL použít absolutní adresu URL. U žádostí mezi doménou přejděte .withUrl("/chathub") na .withUrl("https://{App domain name}/chathub").

Aby se zabránilo škodlivému webu ve čtení citlivých dat z jiného webu, jsou ve výchozím nastavení zakázaná připojení mezi zdroji. Pokud chcete povolit žádost mezi zdroji, povolte 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 musí být volána před voláním MapHub.

Metody centra volání z klienta

Klienti JavaScriptu volají veřejné metody v centrech prostřednictvím metody vyvolání HubConnection. Metoda invoke přijímá:

  • Název metody centra.
  • Všechny argumenty definované v metodě centra.

V následujícím zvýrazněném kódu je SendMessagenázev metody v centru . Druhý a třetí argument předaný pro invoke mapování na metody user centra a message argumenty:

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Volání metod centra z klienta je podporováno pouze při použití služby Azure SignalR ve výchozím režimu. Další informace najdete v tématu Nejčastější dotazy (úložiště Azure–signalr GitHub).

Metoda invoke vrátí JavaScript Promise. Vyřeší se Promise návratovou hodnotou (pokud existuje), když metoda na serveru vrátí. Pokud metoda na serveru vyvolá chybu, Promise je odmítnuta s chybovou zprávou. K řešení těchto případů použijte async a await nebo Promisemetody then a catch metody.

Klienti JavaScriptu mohou také volat veřejné metody v centrech prostřednictvím metody HubConnectionodeslání . invoke Na rozdíl od metody metoda send nečeká na odpověď ze serveru. Metoda send vrátí JavaScript Promise. Tato Promise zpráva se vyřeší, když se zpráva odešle na server. Pokud dojde k chybě při odesílání zprávy, Promise zpráva se odmítne s chybovou zprávou. K řešení těchto případů použijte async a await nebo Promisemetody then a catch metody.

Použití send nečeká na přijetí zprávy serverem. V důsledku toho není možné ze serveru vracet data ani chyby.

Volání metod klienta z centra

Chcete-li přijímat zprávy z centra, definujte metodu pomocí metody on metoda HubConnection.

  • Název metody klienta JavaScriptu.
  • Argumenty, které centrum předá metodě.

V následujícím příkladu je ReceiveMessagenázev metody . Názvy argumentů jsou user a message:

connection.on("ReceiveMessage", (user, message) => {
    const li = document.createElement("li");
    li.textContent = `${user}: ${message}`;
    document.getElementById("messageList").appendChild(li);
});

Předchozí kód se connection.on spustí při volání kódu na straně serveru pomocí SendAsync metody:

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 určuje, kterou metodu klienta se má volat podle názvu metody a argumentů definovaných v SendAsync a connection.on.

Osvědčeným postupem je volat metodu start na HubConnection následující on. Tím zajistíte, aby obslužné rutiny byly registrovány před přijetím všech zpráv.

Zpracování chyb a protokolování

Umožňuje console.error vypsat chyby do konzoly prohlížeče, když se klient nemůže připojit nebo odeslat zprávu:

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Nastavte trasování protokolu na straně klienta předáním protokolovacího nástroje a typu události, která se má protokolovat při vytváření připojení. Zprávy se protokolují se zadanou úrovní protokolu a vyšší. Dostupné úrovně protokolů jsou následující:

  • signalR.LogLevel.Error: Chybové zprávy. Protokoluje Error pouze zprávy.
  • signalR.LogLevel.Warning: Upozornění na potenciální chyby. Protokoly Warninga Error zprávy.
  • signalR.LogLevel.Information: Stavové zprávy bez chyb. Protokoly Informationa WarningError zprávy.
  • signalR.LogLevel.Trace: Trasování zpráv. Zaznamená všechno, včetně dat přenášených mezi centrem a klientem.

Ke konfiguraci úrovně protokolu použijte metodu configureLogging na HubConnectionBuilder . Zprávy se protokolují do konzoly prohlížeče:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Information)
    .build();

Opětovné připojení klientů

Automatické opětovné připojení

Klienta JavaScriptu pro SignalR lze nakonfigurovat tak, aby se automaticky znovu připojil pomocí metody WithAutomaticReconnect v HubConnectionBuilder. Ve výchozím nastavení se automaticky nepřipojí.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect()
    .build();

Bez jakýchkoli parametrů nakonfiguruje WithAutomaticReconnect klienta tak, aby čekal 0, 2, 10 a 30 sekund před pokusem o opětovné připojení. Po čtyřech neúspěšných pokusech se přestane znovu připojovat.

Před zahájením jakýchkoli pokusů o opětovné připojení:HubConnection

  • Přejde do HubConnectionState.Reconnecting stavu a aktivuje zpětná onreconnecting volání.
  • Nepřechází do Disconnected stavu a neaktivuje zpětná onclose volání jako HubConnection bez konfigurace automatického opětovného připojení.

Přístup k opětovnému připojení poskytuje příležitost:

  • Upozornit uživatele, že připojení bylo ztraceno.
  • Zakažte prvky uživatelského rozhraní.
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);
});

Pokud se klient úspěšně znovu připojí během prvních čtyř pokusů, HubConnection přechody zpět do Connected stavu a aktivují zpětná onreconnected volání. To poskytuje možnost informovat uživatele, že připojení bylo znovu obnoveno.

Vzhledem k tomu, že připojení na serveru vypadá zcela nové, poskytuje onreconnected se zpětná connectionId volání.

Parametr onreconnected zpětného connectionId volání není definován, pokud HubConnection je nakonfigurovaný tak, aby přeskočí vyjednávání.

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 nenakonfiguruje HubConnection opakování neúspěšných počátečních spuštění, takže chyby spuštění je potřeba zpracovat ručně:

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);
    }
};

Pokud se klient během prvních čtyř pokusů úspěšně nepřipojí, HubConnection přejde do Disconnected stavu a aktivuje zpětná volání onkose . To poskytuje příležitost informovat uživatele:

  • Připojení bylo trvale ztraceno.
  • Zkuste aktualizovat stránku:
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);
});

Pokud chcete nakonfigurovat vlastní počet pokusů o opětovné připojení před odpojením nebo změnou časování opětovného připojení, withAutomaticReconnect přijme pole čísel představující zpoždění v milisekundách, aby se čekalo před zahájením každého pokusu o opětovné připojení.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect([0, 0, 10000])
    .build();

    // .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior

Předchozí příklad nakonfiguruje HubConnection pokus o opětovné připojení okamžitě po ztrátě připojení. Výchozí konfigurace také čeká nula sekund, než se pokusí znovu připojit.

Pokud první pokus o opětovné připojení selže, druhý pokus o opětovné připojení se spustí také okamžitě místo čekání 2 sekund pomocí výchozí konfigurace.

Pokud druhý pokus o opětovné připojení selže, spustí se třetí pokus o opětovné připojení za 10 sekund, což je stejné jako výchozí konfigurace.

Nakonfigurované časování opětovného připojení se liší od výchozího chování zastavením po selhání třetího pokusu o opětovné připojení místo pokusu o další pokus o opětovné připojení za dalších 30 sekund.

Pro větší kontrolu nad časováním a počtem automatických pokusů o withAutomaticReconnect opětovné připojení přijímá objekt implementuje IRetryPolicy rozhraní, který má jednu metodu s názvem nextRetryDelayInMilliseconds.

nextRetryDelayInMilliseconds přebírá jeden argument s typem RetryContext. Má RetryContext tři vlastnosti: previousRetryCounta elapsedMilliseconds retryReason které jsou , numbernumber a Error v uvedeném pořadí. Před prvním opakovaným pokusem o připojení bude nula previousRetryCount elapsedMilliseconds a retryReason chyba, která způsobila ztrátu připojení. Po každém neúspěšném pokusu o previousRetryCount opakování se zvýší o jeden, elapsedMilliseconds aktualizuje se tak, aby odrážel dobu strávenou opětovným připojením v milisekundách a retryReason chyba, která způsobila poslední pokus o opětovné připojení k selhání.

nextRetryDelayInMilliseconds musí vrátit číslo představující počet milisekund, které se mají počkat před dalším pokusem o opětovné připojení, nebo null pokud HubConnection by se mělo znovu připojit.

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();

Případně můžete napsat kód, který klienta znovu připojí ručně, jak je znázorněno v následující části.

Ruční opětovné připojení

Následující kód ukazuje typický přístup k ručnímu opětovnému připojení:

  1. Vytvoří se funkce (v tomto případě start funkce) pro spuštění připojení.
  2. start Volání funkce v obslužné rutině onclose události připojení.
async function start() {
    try {
        await connection.start();
        console.log("SignalR Connected.");
    } catch (err) {
        console.log(err);
        setTimeout(start, 5000);
    }
};

connection.onclose(async () => {
    await start();
});

Produkční implementace obvykle používají exponenciální zpětné vypnutí nebo opakují zadaný počet opakování.

Karta Spánku prohlížeče

Některé prohlížeče mají funkci zamrznutí tabulátoru nebo režimu spánku, která snižuje využití prostředků počítače pro neaktivní karty. To může způsobit SignalR zavření připojení a může vést k nežádoucímu uživatelskému prostředí. Prohlížeče používají heuristiku k zjištění, jestli se má karta umístit do režimu spánku, například:

  • Přehrávání zvuku
  • Podržení zámku webu
  • Podržení IndexedDB zámku
  • Připojení k zařízení USB
  • Zachytávání videa nebo zvuku
  • Zrcadlení
  • Zachycení okna nebo zobrazení

Heuristika prohlížeče se může v průběhu času měnit a může se mezi prohlížeči lišit. Projděte si matici podpory a zjistěte, jaká metoda je pro vaše scénáře nejvhodnější.

Aby se zabránilo umístění aplikace do režimu spánku, měla by aplikace aktivovat jednu z heuristik, které prohlížeč používá.

Následující příklad kódu ukazuje, jak pomocí webového zámku udržet kartu vzhůru a vyhnout se neočekávanému uzavření připojení.

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;
    });
}

Pro předchozí příklad kódu:

  • Webové zámky jsou experimentální. Podmíněná kontrola potvrzuje, že prohlížeč podporuje webové zámky.
  • Překladač příslibů je uložený tak, lockResolveraby zámek mohl být uvolněn, když je přijatelná pro kartu do režimu spánku.
  • Při zavírání připojení se zámek uvolní voláním lockResolver(). Jakmile se zámek uvolní, karta může spát.

Další materiály

Autor: Rachel Appel

Klientská knihovna ASP.NET Core SignalR JavaScript umožňuje vývojářům volat kód centra na straně serveru.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

SignalR Instalace balíčku klienta

Klientská SignalR knihovna JavaScriptu se doručí jako balíček npm . Následující části popisují různé způsoby instalace klientské knihovny.

Instalace pomocí npm

Pro Visual Studio spusťte v kořenové složce následující příkazy z konzoly Správce balíčků. Pro Visual Studio Code spusťte z integrovaného terminálu následující příkazy.

npm init -y
npm install @microsoft/signalr

npm nainstaluje obsah balíčku do složky node_modules\@microsoft\signalr\dist\browser . Vytvořte novou složku s názvem signalr wwwroot\lib . signalr.js Zkopírujte soubor do složky wwwroot\lib\signalr.

Odkazovat na javascriptového SignalR klienta v elementu <script> . Příklad:

<script src="~/lib/signalr/signalr.js"></script>

Použití sítě pro doručování obsahu (CDN)

Chcete-li použít klientskou knihovnu bez předpokladu npm, odkazujte na kopii klientské knihovny hostované v CDN. Příklad:

<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.js"></script>

Klientská knihovna je k dispozici v následujících sítích CDN:

Instalace pomocí nástroje LibMan

Knihovnu LibMan lze použít k instalaci konkrétních souborů klientské knihovny z klientské knihovny hostované v CDN. Například do projektu přidejte pouze minifikovaný javascriptový soubor. Podrobnosti o tomto přístupu najdete v SignalR tématu Přidání klientské knihovny.

Připojení k centru

Následující kód vytvoří a spustí připojení. Název centra nerozlišuje velká a malá písmena:

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();

Připojení mezi zdroji

Prohlížeče obvykle načítají připojení ze stejné domény jako požadovaná stránka. Existují však situace, kdy se vyžaduje připojení k jiné doméně.

Důležité

Kód klienta musí místo relativní adresy URL použít absolutní adresu URL. Změňte .withUrl("/chathub") na .withUrl("https://myappurl/chathub").

Aby se zabránilo škodlivému webu ve čtení citlivých dat z jiného webu, jsou ve výchozím nastavení zakázaná připojení mezi zdroji. Pokud chcete povolit požadavek mezi zdroji, povolte ho Startup ve třídě:

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");
            });
        }
    }
}

Metody centra volání z klienta

Klienti JavaScriptu volají veřejné metody v centrech prostřednictvím metody vyvolání HubConnection. Metoda invoke přijímá:

  • Název metody centra.
  • Všechny argumenty definované v metodě centra.

V následujícím příkladu je název metody v centru .SendMessage Druhý a třetí argument předaný pro invoke mapování na metody user centra a message argumenty:

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Poznámka:

Volání metod centra z klienta je podporováno pouze při použití služby Azure SignalR ve výchozím režimu. Další informace najdete v tématu Nejčastější dotazy (úložiště Azure–signalr GitHub).

Metoda invoke vrátí JavaScript Promise. Vyřeší se Promise návratovou hodnotou (pokud existuje), když metoda na serveru vrátí. Pokud metoda na serveru vyvolá chybu, Promise je odmítnuta s chybovou zprávou. K řešení těchto případů použijte async a await nebo Promisemetody then a catch metody.

Klienti JavaScriptu mohou také volat veřejné metody v centrech prostřednictvím metody HubConnectionodeslání . invoke Na rozdíl od metody metoda send nečeká na odpověď ze serveru. Metoda send vrátí JavaScript Promise. Tato Promise zpráva se vyřeší, když se zpráva odešle na server. Pokud dojde k chybě při odesílání zprávy, Promise zpráva se odmítne s chybovou zprávou. K řešení těchto případů použijte async a await nebo Promisemetody then a catch metody.

Poznámka:

Použití send nečeká na přijetí zprávy serverem. V důsledku toho není možné ze serveru vracet data ani chyby.

Volání metod klienta z centra

Chcete-li přijímat zprávy z centra, definujte metodu pomocí metody on metoda HubConnection.

  • Název metody klienta JavaScriptu.
  • Argumenty, které centrum předá metodě.

V následujícím příkladu je ReceiveMessagenázev metody . Názvy argumentů jsou user a message:

connection.on("ReceiveMessage", (user, message) => {
    const li = document.createElement("li");
    li.textContent = `${user}: ${message}`;
    document.getElementById("messageList").appendChild(li);
});

Předchozí kód se connection.on spustí při volání kódu na straně serveru pomocí SendAsync metody:

public async Task SendMessage(string user, string message)
{
    await Clients.All.SendAsync("ReceiveMessage", user, message);
}

SignalR určuje, kterou metodu klienta se má volat podle názvu metody a argumentů definovaných v SendAsync a connection.on.

Poznámka:

Osvědčeným postupem je volat metodu start na HubConnection následující on. Tím zajistíte, aby obslužné rutiny byly zaregistrovány před přijetím všech zpráv.

Zpracování chyb a protokolování

Používejte try a catch s async metodou a await nebo metodou catch Promisezpracování chyb na straně klienta. Slouží console.error k výstupu chyb do konzoly prohlížeče:

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Nastavte trasování protokolu na straně klienta předáním protokolovacího nástroje a typu události, která se má protokolovat při vytváření připojení. Zprávy se protokolují se zadanou úrovní protokolu a vyšší. Dostupné úrovně protokolů jsou následující:

  • signalR.LogLevel.Error: Chybové zprávy. Protokoluje Error pouze zprávy.
  • signalR.LogLevel.Warning: Upozornění na potenciální chyby. Protokoly Warninga Error zprávy.
  • signalR.LogLevel.Information: Stavové zprávy bez chyb. Protokoly Informationa WarningError zprávy.
  • signalR.LogLevel.Trace: Trasování zpráv. Zaznamená všechno, včetně dat přenášených mezi centrem a klientem.

Ke konfiguraci úrovně protokolu použijte metodu configureLogging na HubConnectionBuilder . Zprávy se protokolují do konzoly prohlížeče:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Information)
    .build();

Opětovné připojení klientů

Automatické opětovné připojení

Klienta JavaScriptu pro SignalR lze nakonfigurovat tak, aby se automaticky znovu připojil pomocí withAutomaticReconnect metody v HubConnectionBuilder. Ve výchozím nastavení se automaticky nepřipojí.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect()
    .build();

Bez jakýchkoli parametrů nakonfiguruje klienta tak, withAutomaticReconnect() aby čekal 0, 2, 10 a 30 sekund před pokusem o opětovné připojení a zastavil se po čtyřech neúspěšných pokusech.

Před zahájením jakýchkoli pokusů o HubConnection opětovné připojení přejde do HubConnectionState.Reconnecting stavu a aktivuje zpětná onreconnecting volání místo přechodu na Disconnected stav a aktivuje zpětná onclose volání jako HubConnection bez automatického opětovného připojení nakonfigurované. To poskytuje možnost upozornit uživatele, že připojení bylo ztraceno a zakázat prvky uživatelského rozhraní.

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);
});

Pokud se klient úspěšně znovu připojí během prvních čtyř pokusů, HubConnection přejde zpět do Connected stavu a aktivuje zpětná onreconnected volání. To poskytuje možnost informovat uživatele, že připojení bylo znovu obnoveno.

Vzhledem k tomu, že připojení na serveru vypadá zcela nové, bude zpětnému onreconnected volání poskytováno novéconnectionId.

Upozorňující

Parametr onreconnected zpětného connectionId volání nebude definován, pokud HubConnection byl nakonfigurován tak, aby přeskočí vyjednávání.

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() nenakonfiguruje HubConnection opakování neúspěšných počátečních spuštění, takže chyby spuštění je potřeba zpracovat ručně:

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);
    }
};

Pokud se klient během prvních čtyř pokusů úspěšně nepřipojí, HubConnection přejde do Disconnected stavu a aktivuje zpětná volání. To poskytuje příležitost informovat uživatele, že připojení bylo trvale ztraceno a doporučit aktualizaci stránky:

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);
});

Pokud chcete nakonfigurovat vlastní počet pokusů o opětovné připojení před odpojením nebo změnou časování opětovného připojení, withAutomaticReconnect přijme pole čísel představující zpoždění v milisekundách, aby se čekalo před zahájením každého pokusu o opětovné připojení.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect([0, 0, 10000])
    .build();

    // .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior

Předchozí příklad nakonfiguruje HubConnection pokus o opětovné připojení okamžitě po ztrátě připojení. To platí i pro výchozí konfiguraci.

Pokud první pokus o opětovné připojení selže, druhý pokus o opětovné připojení se spustí také okamžitě místo čekání na 2 sekundy, jako by byl ve výchozí konfiguraci.

Pokud druhý pokus o opětovné připojení selže, třetí pokus o opětovné připojení se spustí za 10 sekund, což je znovu jako výchozí konfigurace.

Vlastní chování se pak znovu liší od výchozího chování zastavením po selhání třetího pokusu o opětovné připojení místo pokusu o další pokus o opětovné připojení za dalších 30 sekund, jako by to bylo ve výchozí konfiguraci.

Chcete-li ještě větší kontrolu nad časováním a počtem automatických pokusů o opětovné připojení, withAutomaticReconnect přijímá objekt implementuje IRetryPolicy rozhraní, který má jednu metodu s názvem nextRetryDelayInMilliseconds.

nextRetryDelayInMilliseconds přebírá jeden argument s typem RetryContext. Má RetryContext tři vlastnosti: previousRetryCounta elapsedMilliseconds retryReason které jsou , numbernumber a Error v uvedeném pořadí. Před prvním opakovaným pokusem o připojení bude nula previousRetryCount elapsedMilliseconds a retryReason chyba, která způsobila ztrátu připojení. Po každém neúspěšném pokusu o previousRetryCount opakování se zvýší o jeden, elapsedMilliseconds aktualizuje se tak, aby odrážel dobu strávenou opětovným připojením v milisekundách a retryReason chyba, která způsobila poslední pokus o opětovné připojení k selhání.

nextRetryDelayInMilliseconds musí vrátit číslo představující počet milisekund, které se mají počkat před dalším pokusem o opětovné připojení, nebo null pokud HubConnection by se mělo znovu připojit.

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();

Případně můžete napsat kód, který klienta znovu připojí ručně, jak je znázorněno v tématu Ruční opětovné připojení.

Ruční opětovné připojení

Následující kód ukazuje typický přístup k ručnímu opětovnému připojení:

  1. Vytvoří se funkce (v tomto případě start funkce) pro spuštění připojení.
  2. start Volání funkce v obslužné rutině onclose události připojení.
async function start() {
    try {
        await connection.start();
        console.log("SignalR Connected.");
    } catch (err) {
        console.log(err);
        setTimeout(start, 5000);
    }
};

connection.onclose(async () => {
    await start();
});

Produkční implementace obvykle používají exponenciální zpětné vypnutí nebo opakují zadaný počet opakování.

Karta Spánku prohlížeče

Některé prohlížeče mají funkci zamrznutí tabulátoru nebo režimu spánku, která snižuje využití prostředků počítače pro neaktivní karty. To může způsobit SignalR zavření připojení a může vést k nežádoucímu uživatelskému prostředí. Prohlížeče používají heuristiku k zjištění, jestli se má karta umístit do režimu spánku, například:

  • Přehrávání zvuku
  • Podržení zámku webu
  • Podržení IndexedDB zámku
  • Připojení k zařízení USB
  • Zachytávání videa nebo zvuku
  • Zrcadlení
  • Zachycení okna nebo zobrazení

Poznámka:

Tyto heuristiky se můžou v průběhu času měnit nebo se mezi prohlížeči liší. Zkontrolujte matici podpory a zjistěte, jakou metodu je pro vaše scénáře nejvhodnější.

Aby se zabránilo umístění aplikace do režimu spánku, měla by aplikace aktivovat jednu z heuristik, které prohlížeč používá.

Následující příklad kódu ukazuje, jak pomocí webového zámku udržet kartu vzhůru a vyhnout se neočekávanému uzavření připojení.

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;
    });
}

Pro předchozí příklad kódu:

  • Webové zámky jsou experimentální. Podmíněná kontrola potvrzuje, že prohlížeč podporuje webové zámky.
  • Překladač příslibů (lockResolver) je uložený tak, aby se zámek mohl uvolnit, až bude karta přijatelná pro režim spánku.
  • Při zavírání připojení se zámek uvolní voláním lockResolver(). Jakmile se zámek uvolní, karta může spát.

Další materiály