ASP.NET Core SignalR JavaScript 클라이언트
작성자: Rachel Appel
ASP.NET Core SignalR JavaScript 클라이언트 라이브러리를 사용하면 개발자가 서버 쪽 SignalR 허브 코드를 호출할 수 있습니다.
SignalR 클라이언트 패키지를 설치합니다.
SignalR JavaScript 클라이언트 라이브러리는 npm 패키지로 전달됩니다. 다음 섹션에서는 클라이언트 라이브러리를 설치하는 다양한 방법을 간략하게 설명합니다.
npm을 사용하여 설치
패키지 관리자 콘솔에서 다음 명령을 실행합니다.
npm init -y
npm install @microsoft/signalr
npm은 node_modules\@microsoft\\dist\signalrbrowser 폴더에 패키지 콘텐츠를 설치합니다. wwwroot/lib/signalr 폴더를 만듭니다. signalr.js
파일을 wwwroot/lib/signalr 폴더에 복사합니다.
<script>
요소에서 SignalR JavaScript 클라이언트를 참조합니다. 예시:
<script src="~/lib/signalr/signalr.js"></script>
CDN(콘텐츠 배달 네트워크) 사용
npm 필수 조건 없이 클라이언트 라이브러리를 사용하려면 클라이언트 라이브러리의 CDN 호스팅 복사본을 참조합니다. 예시:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
클라이언트 라이브러리는 다음 CDN에서 사용할 수 있습니다.
LibMan을 통해 설치
LibMan은 CDN 호스팅 클라이언트 라이브러리에서 특정 클라이언트 라이브러리 파일을 설치하는 데 사용할 수 있습니다. 예를 들어 축소된 JavaScript 파일만 프로젝트에 추가합니다. 이 접근 방식에 대한 자세한 내용은 SignalR 클라이언트 라이브러리 추가를 참조하세요.
허브에 연결
다음 코드는 연결을 만들고 시작합니다. 허브의 이름은 대소문자를 구분하지 않습니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Start the connection.
start();
원본 간 연결(CORS)
일반적으로 브라우저는 요청된 페이지와 동일한 도메인에서 연결을 로드합니다. 그러나 다른 도메인에 대한 연결이 필요한 경우도 있습니다.
도메인 간 요청을 할 때 클라이언트 코드는 상대 URL 대신 절대 URL을 사용해야 합니다. 도메인 간 요청의 경우 .withUrl("/chathub")
를 .withUrl("https://{App domain name}/chathub")
로 변경합니다.
악의적인 사이트가 다른 사이트에서 중요한 데이터를 읽지 못하도록 하려면 기본적으로 원본 간 연결은 사용하지 않도록 설정됩니다. 원본 간 요청을 허용하려면 CORS를 사용하도록 설정합니다.
using SignalRChat.Hubs;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://example.com")
.AllowAnyHeader()
.WithMethods("GET", "POST")
.AllowCredentials();
});
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// UseCors must be called before MapHub.
app.UseCors();
app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
app.Run();
MapHub를 호출하기 전에 UseCors를 호출해야 합니다.
클라이언트에서 허브 메서드 호출
JavaScript 클라이언트는 HubConnection의 invoke 메서드를 통해 허브에서 공용 메서드를 호출합니다. invoke
메서드는 다음을 허용합니다.
- 허브 메서드의 이름.
- 허브 메서드에 정의된 인수.
다음 강조 표시된 코드에서 허브의 메서드 이름은 SendMessage
입니다. invoke
에 전달된 두 번째 및 세 번째 인수는 허브 메서드의 user
및 message
인수에 매핑됩니다.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
클라이언트에서 허브 메서드를 호출하는 것은 기본 모드에서 Azure SignalR Service를 사용하는 경우에만 지원됩니다. 자세한 내용은 질문과 대답(azure-signalr GitHub 리포지토리)을 참조하세요.
invoke
메서드는 JavaScript Promise
를 반환합니다. Promise
는 서버의 메서드가 반환될 때 반환 값(있는 경우)으로 확인됩니다. 서버의 메서드가 오류를 throw하는 경우 Promise
는 오류 메시지와 함께 거부됩니다. async
및 await
또는 Promise
의 then
및 catch
메서드를 사용하여 이러한 사례를 처리합니다.
JavaScript 클라이언트는 HubConnection
의 send 메서드를 통해 허브에서 공용 메서드를 호출합니다. invoke
메서드와 달리 send
메서드는 서버의 응답을 기다리지 않습니다. send
메서드는 JavaScript Promise
를 반환합니다. Promise
는 메시지가 서버로 전송될 때 확인됩니다. 메시지를 보내는 동안 오류가 발생하면 오류 메시지와 함께 Promise
가 거부됩니다. async
및 await
또는 Promise
의 then
및 catch
메서드를 사용하여 이러한 사례를 처리합니다.
서버 send
에서 메시지를 받을 때까지 기다리지 않습니다 . 따라서 서버에서 데이터 또는 오류를 반환할 수 없습니다.
허브에서 클라이언트 메서드 호출
허브에서 메시지를 받으려면 HubConnection
의 on 메서드를 사용하여 메서드를 정의합니다.
- JavaScript 클라이언트 메서드의 이름.
- 허브가 메서드에 전달하는 인수.
다음 예제에서 메서드 이름은 ReceiveMessage
입니다. 인수 이름은 user
및 message
입니다.
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messageList").appendChild(li);
});
connection.on
의 이전 코드는 서버 쪽 코드가 SendAsync 메서드를 사용하여 호출할 때 실행됩니다.
using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs;
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
SignalR은 SendAsync
및 connection.on
에 정의된 메서드 이름과 인수를 일치시켜 호출할 클라이언트 메서드를 결정합니다.
가장 좋은 방법은 on
다음 HubConnection
에서 start 메서드를 호출하는 것입니다. 이렇게 하면 메시지를 받기 전에 처리기가 등록됩니다.
오류 처리 및 로깅
클라이언트에서 메시지를 연결하거나 보낼 수 없는 경우 console.error
을 사용하여 브라우저 콘솔에 오류를 출력합니다.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
연결이 설정되면 기록할 이벤트 유형 및 로거를 전달하여 클라이언트 쪽 로그 추적을 설정합니다. 메시지는 지정된 로그 수준 이상으로 기록됩니다. 사용 가능한 로그 수준은 다음과 같습니다.
signalR.LogLevel.Error
: 오류 메시지.Error
메시지만 기록합니다.signalR.LogLevel.Warning
: 잠재적 오류에 대한 경고 메시지입니다.Warning
및Error
메시지를 기록합니다.signalR.LogLevel.Information
: 오류 없는 상태 메시지입니다.Information
,Warning
및Error
메시지를 기록합니다.signalR.LogLevel.Trace
: 추적 메시지. 허브와 클라이언트 간에 전송되는 데이터를 포함하여 모든 것을 기록합니다.
HubConnectionBuilder의 configureLogging 메서드를 사용하여 로그 수준을 구성합니다. 메시지가 브라우저 콘솔에 기록됩니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
클라이언트 다시 연결
자동으로 다시 연결
HubConnectionBuilder의 WithAutomaticReconnect 메서드를 사용하여 자동으로 다시 연결하도록 SignalR에 대한 JavaScript 클라이언트를 구성할 수 있습니다. 기본적으로 자동으로 다시 연결되지 않습니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
매개 변수를 사용하지 않으면 WithAutomaticReconnect는 클라이언트가 각각 0초, 2초, 10초 및 30초를 기다린 후 각 다시 연결 시도를 시도하도록 구성합니다. 네 번의 시도가 실패한 후 다시 연결 시도를 중지합니다.
다시 연결 시도를 시작하기 전에 HubConnection
에서 다음을 수행합니다.
HubConnectionState.Reconnecting
상태로 전환하고onreconnecting
콜백을 실행합니다.Disconnected
상태로 전환하지 않고 자동 다시 연결이 구성되지 않은HubConnection
와 같은onclose
콜백을 트리거합니다.
다시 연결 방법은 다음을 수행할 수 있는 기회를 제공합니다.
- 연결이 끊어졌는지 사용자에게 경고합니다.
- 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);
});
클라이언트가 처음 네 번의 시도 내에서 성공적으로 다시 연결되면 HubConnection
이 Connected
상태로 다시 전환되고 onreconnected
콜백을 실행합니다. 이렇게 하면 연결이 다시 구성되었다는 것을 사용자에게 알릴 수 있습니다.
연결은 서버에 완전히 새로운 것으로 보이므로 onreconnected
콜백에 새 connectionId
가 제공됩니다.
HubConnection
이 건너뛰기 협상으로 구성된 경우 onreconnected
콜백의 connectionId
매개 변수가 정의되지 않습니다.
connection.onreconnected(connectionId => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
document.getElementById("messageInput").disabled = false;
const li = document.createElement("li");
li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
document.getElementById("messageList").appendChild(li);
});
withAutomaticReconnect
는 초기 시작 오류를 다시 시도하도록 HubConnection
을 구성하지 않으므로 시작 실패를 수동으로 처리해야 합니다.
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("SignalR Connected.");
} catch (err) {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
console.log(err);
setTimeout(() => start(), 5000);
}
};
클라이언트가 처음 네 번의 시도 내에서 성공적으로 다시 연결되지 않으면 HubConnection
이 Disconnected
상태로 전환되고 onclose 콜백을 실행합니다. 이렇게 하면 사용자에게 다음을 알릴 수 있습니다.
- 연결이 영구적으로 끊겼습니다.
- 페이지를 새로 고침해 보세요.
connection.onclose(error => {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
document.getElementById("messageList").appendChild(li);
});
연결을 끊거나 다시 연결 시간을 변경하기 전에 사용자 지정 다시 연결 시도 횟수를 구성하기 위해 withAutomaticReconnect
는 각 다시 연결 시도를 시작하기 전에 대기할 지연 시간(밀리초)을 나타내는 일련의 숫자를 수락합니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
앞의 예제에서는 연결이 끊긴 후 즉시 다시 연결 시도를 시작하도록 HubConnection
을 구성합니다. 기본 구성은 다시 연결을 시도하기 위해 0초 동안 대기합니다.
첫 번째 다시 연결 시도가 실패하면 두 번째 다시 연결 시도도 기본 구성을 사용하여 2초 동안 대기하는 대신 즉시 시작됩니다.
두 번째 다시 연결 시도가 실패하면 세 번째 다시 연결 시도는 기본 구성과 동일하게 10초 후에 시작됩니다.
구성된 다시 연결 타이밍은 30초 후에 다시 연결 시도를 한 번 더 시도하는 대신 세 번째 다시 연결 시도 실패 후 중지하여 기본 동작과 다릅니다.
자동 다시 연결 시도의 타이밍과 수를 더 많이 제어하려는 경우 withAutomaticReconnect
는 nextRetryDelayInMilliseconds
라는 단일 메서드가 있는 IRetryPolicy
인터페이스를 구현하는 개체를 허용합니다.
nextRetryDelayInMilliseconds
는 RetryContext
형식의 단일 인수를 사용합니다. RetryContext
에는 각각 number
, number
및 Error
인 세 가지 속성 previousRetryCount
, elapsedMilliseconds
및 retryReason
이 있습니다. 첫 번째 다시 연결 시도 전에 previousRetryCount
및 elapsedMilliseconds
는 모두 0이 되고 retryReason
은 연결이 끊어지도록 하는 오류가 됩니다. 실패한 각 재시도 후에는 previousRetryCount
가 1씩 증가하고, 지금까지 다시 연결하는 데 걸린 시간(밀리초)을 반영하도록 elapsedMilliseconds
가 업데이트되며, retryReason
은 마지막 다시 연결 시도의 실패를 초래한 오류입니다.
HubConnection
이 다시 연결을 중지해야 하는 경우 nextRetryDelayInMilliseconds
는 다음 다시 연결 시도까지 대기할 시간(밀리초)을 나타내는 숫자 또는 null
을 반환해야 합니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: retryContext => {
if (retryContext.elapsedMilliseconds < 60000) {
// If we've been reconnecting for less than 60 seconds so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
return Math.random() * 10000;
} else {
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
}
})
.build();
또는 다음 섹션에 설명된 대로 클라이언트를 수동으로 다시 연결하는 코드를 작성할 수 있습니다.
수동으로 다시 연결
다음 코드는 일반적인 수동 다시 연결 방법을 설명합니다.
- 연결을 시작하는 함수(이 경우
start
함수)가 만들어집니다. - 연결의
onclose
이벤트 처리기에서start
함수를 호출합니다.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
프로덕션 구현은 일반적으로 지수 백오프를 사용하거나 지정된 횟수를 다시 시도합니다.
브라우저 절전 모드 탭
일부 브라우저에는 비활성 탭에 대한 컴퓨터 리소스 사용량을 줄이기 위한 탭 고정 또는 절전 모드 기능이 있습니다. 이로 인해 SignalR 연결이 닫힐 수 있으며 원치 않는 사용자 환경이 발생할 수 있습니다. 브라우저는 추론을 사용하여 다음과 같이 탭을 절전 모드로 유지해야 하는지 파악합니다.
- 오디오 재생
- 웹 잠금 유지
IndexedDB
잠금 유지- USB 디바이스에 연결
- 비디오 또는 오디오 캡처
- 미러되는 중
- 창 또는 디스플레이 캡처
브라우저 추론은 시간이 지남에 따라 변경되고 브라우저 간에 다를 수 있습니다. 지원 매트릭스를 확인하고 시나리오에 가장 적합한 방법을 알아보세요.
앱을 절전 모드로 두지 않으려면 앱이 브라우저에서 사용하는 추론 중 하나를 트리거해야 합니다.
다음 코드 예제에서는 웹 잠금을 사용하여 탭을 끊은 상태로 유지하고 예기치 않은 연결 닫기를 방지하는 방법을 보여 줍니다.
var lockResolver;
if (navigator && navigator.locks && navigator.locks.request) {
const promise = new Promise((res) => {
lockResolver = res;
});
navigator.locks.request('unique_lock_name', { mode: "shared" }, () => {
return promise;
});
}
이전 코드 예제에서:
- 웹 잠금은 실험적입니다. 조건부 검사는 브라우저가 웹 잠금을 지원하는지 확인합니다.
- 약속 확인자인
lockResolver
는 탭이 절전 모드로 있을 수 있을 때 잠금을 해제할 수 있도록 저장됩니다. - 연결을 닫으면
lockResolver()
를 호출하여 잠금이 해제됩니다. 잠금이 해제되면 탭이 절전 모드로 있을 수 있습니다.
추가 리소스
작성자: Rachel Appel
ASP.NET Core SignalR JavaScript 클라이언트 라이브러리를 사용하면 개발자가 서버 쪽 허브 코드를 호출할 수 있습니다.
SignalR 클라이언트 패키지를 설치합니다.
SignalR JavaScript 클라이언트 라이브러리는 npm 패키지로 전달됩니다. 다음 섹션에서는 클라이언트 라이브러리를 설치하는 다양한 방법을 간략하게 설명합니다.
npm을 사용하여 설치
Visual Studio의 경우 루트 폴더에 있는 동안 패키지 관리자 콘솔에서 다음 명령을 실행합니다. Visual Studio Code의 경우 통합 터미널에서 다음 명령을 실행합니다.
npm init -y
npm install @microsoft/signalr
npm은 node_modules\@microsoft\\dist\signalrbrowser 폴더에 패키지 콘텐츠를 설치합니다. wwwroot\lib 폴더 아래에 명명된 signalr 새 폴더를 만듭니다. signalr.js
파일을 wwwroot\lib\signalr 폴더에 복사합니다.
<script>
요소에서 SignalR JavaScript 클라이언트를 참조합니다. 예시:
<script src="~/lib/signalr/signalr.js"></script>
CDN(콘텐츠 배달 네트워크) 사용
npm 필수 조건 없이 클라이언트 라이브러리를 사용하려면 클라이언트 라이브러리의 CDN 호스팅 복사본을 참조합니다. 예시:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.js"></script>
클라이언트 라이브러리는 다음 CDN에서 사용할 수 있습니다.
LibMan을 통해 설치
LibMan은 CDN 호스팅 클라이언트 라이브러리에서 특정 클라이언트 라이브러리 파일을 설치하는 데 사용할 수 있습니다. 예를 들어 축소된 JavaScript 파일만 프로젝트에 추가합니다. 이 접근 방식에 대한 자세한 내용은 SignalR 클라이언트 라이브러리 추가를 참조하세요.
허브에 연결
다음 코드는 연결을 만들고 시작합니다. 허브의 이름은 대소문자를 구분하지 않습니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Start the connection.
start();
원본 간 연결
일반적으로 브라우저는 요청된 페이지와 동일한 도메인에서 연결을 로드합니다. 그러나 다른 도메인에 대한 연결이 필요한 경우도 있습니다.
Important
클라이언트 코드는 상대 URL 대신 절대 URL을 사용해야 합니다. .withUrl("/chathub")
를 .withUrl("https://myappurl/chathub")
로 바꿉니다.
악의적인 사이트가 다른 사이트에서 중요한 데이터를 읽지 못하도록 하려면 기본적으로 원본 간 연결은 사용하지 않도록 설정됩니다. 원본 간 요청을 허용하려면 Startup
클래스에서 사용하도록 설정합니다.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SignalRChat.Hubs;
namespace SignalRChat
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR();
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("https://example.com")
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<ChatHub>("/chathub");
});
}
}
}
클라이언트에서 허브 메서드 호출
JavaScript 클라이언트는 HubConnection의 invoke 메서드를 통해 허브에서 공용 메서드를 호출합니다. invoke
메서드는 다음을 허용합니다.
- 허브 메서드의 이름.
- 허브 메서드에 정의된 인수.
다음 예제에서 허브의 메서드 이름은 SendMessage
입니다. invoke
에 전달된 두 번째 및 세 번째 인수는 허브 메서드의 user
및 message
인수에 매핑됩니다.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
참고 항목
클라이언트에서 허브 메서드를 호출하는 것은 기본 모드에서 Azure Service를 사용하는 경우에만 지원됩니다.SignalR 자세한 내용은 질문과 대답(azure-signalr GitHub 리포지토리)을 참조하세요.
invoke
메서드는 JavaScript Promise
를 반환합니다. Promise
는 서버의 메서드가 반환될 때 반환 값(있는 경우)으로 확인됩니다. 서버의 메서드가 오류를 throw하는 경우 Promise
는 오류 메시지와 함께 거부됩니다. async
및 await
또는 Promise
의 then
및 catch
메서드를 사용하여 이러한 사례를 처리합니다.
JavaScript 클라이언트는 HubConnection
의 send 메서드를 통해 허브에서 공용 메서드를 호출합니다. invoke
메서드와 달리 send
메서드는 서버의 응답을 기다리지 않습니다. send
메서드는 JavaScript Promise
를 반환합니다. Promise
는 메시지가 서버로 전송될 때 확인됩니다. 메시지를 보내는 동안 오류가 발생하면 오류 메시지와 함께 Promise
가 거부됩니다. async
및 await
또는 Promise
의 then
및 catch
메서드를 사용하여 이러한 사례를 처리합니다.
참고 항목
send
를 사용하면 서버에서 메시지를 받을 때까지 기다리지 않습니다. 따라서 서버에서 데이터 또는 오류를 반환할 수 없습니다.
허브에서 클라이언트 메서드 호출
허브에서 메시지를 받으려면 HubConnection
의 on 메서드를 사용하여 메서드를 정의합니다.
- JavaScript 클라이언트 메서드의 이름.
- 허브가 메서드에 전달하는 인수.
다음 예제에서 메서드 이름은 ReceiveMessage
입니다. 인수 이름은 user
및 message
입니다.
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messageList").appendChild(li);
});
connection.on
의 이전 코드는 서버 쪽 코드가 SendAsync 메서드를 사용하여 호출할 때 실행됩니다.
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
SignalR은 SendAsync
및 connection.on
에 정의된 메서드 이름과 인수를 일치시켜 호출할 클라이언트 메서드를 결정합니다.
참고 항목
가장 좋은 방법은 on
다음 HubConnection
에서 start 메서드를 호출하는 것입니다. 이렇게 하면 메시지를 받기 전에 처리기가 등록됩니다.
오류 처리 및 로깅
async
및 await
와 함께 try
및 catch
를 사용하거나 Promise
의 catch
메서드를 사용하여 클라이언트 쪽 오류를 처리합니다. console.error
를 사용하여 브라우저의 콘솔에 오류를 출력합니다.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
연결이 설정되면 기록할 이벤트 유형 및 로거를 전달하여 클라이언트 쪽 로그 추적을 설정합니다. 메시지는 지정된 로그 수준 이상으로 기록됩니다. 사용 가능한 로그 수준은 다음과 같습니다.
signalR.LogLevel.Error
: 오류 메시지.Error
메시지만 기록합니다.signalR.LogLevel.Warning
: 잠재적 오류에 대한 경고 메시지입니다.Warning
및Error
메시지를 기록합니다.signalR.LogLevel.Information
: 오류 없는 상태 메시지입니다.Information
,Warning
및Error
메시지를 기록합니다.signalR.LogLevel.Trace
: 추적 메시지. 허브와 클라이언트 간에 전송되는 데이터를 포함하여 모든 것을 기록합니다.
HubConnectionBuilder의 configureLogging 메서드를 사용하여 로그 수준을 구성합니다. 메시지가 브라우저 콘솔에 기록됩니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
클라이언트 다시 연결
자동으로 다시 연결
HubConnectionBuilder의 withAutomaticReconnect
메서드를 사용하여 자동으로 다시 연결하도록 SignalR에 대한 JavaScript 클라이언트를 구성할 수 있습니다. 기본적으로 자동으로 다시 연결되지 않습니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
매개 변수를 사용하지 않으면 withAutomaticReconnect()
는 클라이언트가 각각 0초, 2초, 10초 및 30초를 기다린 후 각 다시 연결 시도를 시도하도록 구성합니다. 네 번의 시도 실패 후 중지됩니다.
다시 연결 시도를 시작하기 전에 HubConnection
은 자동 다시 연결을 구성하지 않고 Disconnected
상태로 전환하고 HubConnection
같은 해당 onclose
콜백을 트리거하는 대신, HubConnectionState.Reconnecting
상태로 전환하고 onreconnecting
콜백을 실행합니다. 이렇게 하면 연결이 손실되었음을 사용자에게 경고하고 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);
});
클라이언트가 처음 네 번의 시도 내에서 성공적으로 다시 연결되면 HubConnection
이 Connected
상태로 다시 전환되고 onreconnected
콜백을 실행합니다. 이렇게 하면 연결이 다시 구성되었다는 것을 사용자에게 알릴 수 있습니다.
연결은 서버에 완전히 새로운 것으로 보이므로 onreconnected
콜백에 새 connectionId
가 제공됩니다.
Warning
HubConnection
이 건너뛰기 협상으로 구성된 경우 onreconnected
콜백의 connectionId
매개 변수가 정의되지 않습니다.
connection.onreconnected(connectionId => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
document.getElementById("messageInput").disabled = false;
const li = document.createElement("li");
li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
document.getElementById("messageList").appendChild(li);
});
withAutomaticReconnect()
는 초기 시작 오류를 다시 시도하도록 HubConnection
을 구성하지 않으므로 시작 실패를 수동으로 처리해야 합니다.
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("SignalR Connected.");
} catch (err) {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
console.log(err);
setTimeout(() => start(), 5000);
}
};
클라이언트가 처음 네 번의 시도 내에서 성공적으로 다시 연결되지 않으면 HubConnection
이 Disconnected
상태로 전환되고 onclose 콜백을 실행합니다. 이렇게 하면 연결이 영구적으로 끊겼음을 사용자에게 알리고 페이지를 새로 고치는 것이 좋습니다.
connection.onclose(error => {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
document.getElementById("messageList").appendChild(li);
});
연결을 끊거나 다시 연결 시간을 변경하기 전에 사용자 지정 다시 연결 시도 횟수를 구성하기 위해 withAutomaticReconnect
는 각 다시 연결 시도를 시작하기 전에 대기할 지연 시간(밀리초)을 나타내는 일련의 숫자를 수락합니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
앞의 예제에서는 연결이 끊긴 후 즉시 다시 연결 시도를 시작하도록 HubConnection
을 구성합니다. 기본 구성의 경우에도 마찬가지입니다.
첫 번째 다시 연결 시도가 실패하면 두 번째 다시 연결 시도도 기본 구성에서와 같이 2초 동안 대기하는 대신 즉시 시작됩니다.
두 번째 다시 연결 시도가 실패하면 세 번째 다시 연결 시도는 기본 구성처럼 10초 후에 시작됩니다.
그런 다음, 사용자 지정 동작은 기본 구성에서와 같이 30초 후에 다시 연결 시도를 한 번 더 시도하는 대신 세 번째 다시 연결 시도 실패 후 중지하여 기본 동작에서 다시 분기합니다.
자동 다시 연결 시도의 타이밍과 수를 더 많이 제어하려는 경우 withAutomaticReconnect
는 nextRetryDelayInMilliseconds
라는 단일 메서드가 있는 IRetryPolicy
인터페이스를 구현하는 개체를 허용합니다.
nextRetryDelayInMilliseconds
는 RetryContext
형식의 단일 인수를 사용합니다. RetryContext
에는 각각 number
, number
및 Error
인 세 가지 속성 previousRetryCount
, elapsedMilliseconds
및 retryReason
이 있습니다. 첫 번째 다시 연결 시도 전에 previousRetryCount
및 elapsedMilliseconds
는 모두 0이 되고 retryReason
은 연결이 끊어지도록 하는 오류가 됩니다. 실패한 각 재시도 후에는 previousRetryCount
가 1씩 증가하고, 지금까지 다시 연결하는 데 걸린 시간(밀리초)을 반영하도록 elapsedMilliseconds
가 업데이트되며, retryReason
은 마지막 다시 연결 시도의 실패를 초래한 오류입니다.
HubConnection
이 다시 연결을 중지해야 하는 경우 nextRetryDelayInMilliseconds
는 다음 다시 연결 시도까지 대기할 시간(밀리초)을 나타내는 숫자 또는 null
을 반환해야 합니다.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: retryContext => {
if (retryContext.elapsedMilliseconds < 60000) {
// If we've been reconnecting for less than 60 seconds so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
return Math.random() * 10000;
} else {
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
}
})
.build();
또는 수동으로 다시 연결에 설명된 대로 클라이언트를 수동으로 다시 연결하는 코드를 작성할 수 있습니다.
수동으로 다시 연결
다음 코드는 일반적인 수동 다시 연결 방법을 설명합니다.
- 연결을 시작하는 함수(이 경우
start
함수)가 만들어집니다. - 연결의
onclose
이벤트 처리기에서start
함수를 호출합니다.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
프로덕션 구현은 일반적으로 지수 백오프를 사용하거나 지정된 횟수를 다시 시도합니다.
브라우저 절전 모드 탭
일부 브라우저에는 비활성 탭에 대한 컴퓨터 리소스 사용량을 줄이기 위한 탭 고정 또는 절전 모드 기능이 있습니다. 이로 인해 SignalR 연결이 닫힐 수 있으며 원치 않는 사용자 환경이 발생할 수 있습니다. 브라우저는 추론을 사용하여 다음과 같이 탭을 절전 모드로 유지해야 하는지 파악합니다.
- 오디오 재생
- 웹 잠금 유지
IndexedDB
잠금 유지- USB 디바이스에 연결
- 비디오 또는 오디오 캡처
- 미러되는 중
- 창 또는 디스플레이 캡처
참고 항목
이러한 추론은 시간이 지남에 따라 변경되거나 브라우저 간에 다를 수 있습니다. 지원 매트릭스를 확인하고 시나리오에 가장 적합한 방법을 알아보세요.
앱을 절전 모드로 두지 않으려면 앱이 브라우저에서 사용하는 추론 중 하나를 트리거해야 합니다.
다음 코드 예제에서는 웹 잠금을 사용하여 탭을 끊은 상태로 유지하고 예기치 않은 연결 닫기를 방지하는 방법을 보여 줍니다.
var lockResolver;
if (navigator && navigator.locks && navigator.locks.request) {
const promise = new Promise((res) => {
lockResolver = res;
});
navigator.locks.request('unique_lock_name', { mode: "shared" }, () => {
return promise;
});
}
이전 코드 예제에서:
- 웹 잠금은 실험적입니다. 조건부 검사는 브라우저가 웹 잠금을 지원하는지 확인합니다.
- 약속 확인자(
lockResolver
)는 탭이 절전 모드로 있을 수 있을 때 잠금을 해제할 수 있도록 저장됩니다. - 연결을 닫으면
lockResolver()
를 호출하여 잠금이 해제됩니다. 잠금이 해제되면 탭이 절전 모드로 있을 수 있습니다.
추가 리소스
ASP.NET Core