다음을 통해 공유


ASP.NET Core 미들웨어 기본 사항

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

작성자: Rick AndersonSteve Smith

미들웨어는 요청 및 응답을 처리하는 앱 파이프라인으로 어셈블리되는 소프트웨어입니다. 각 구성 요소:

  • 요청을 파이프라인의 다음 구성 요소로 전달할지 여부를 선택합니다.
  • 파이프라인의 다음 구성 요소 전과 후에 작업을 수행할 수 있습니다.

요청 대리자는 요청 파이프라인을 빌드하는 데 사용됩니다. 요청 대리자는 각 HTTP 요청을 처리합니다.

요청 대리자는 Run, MapUse 확장 메서드를 사용하여 구성됩니다. 개별 요청 대리자는 무명 메서드(인라인 미들웨어라고 함)로 인라인에서 지정되거나 다시 사용할 수 있는 클래스에서 정의될 수 있습니다. 이러한 다시 사용할 수 있는 클래스 및 인라인 무명 메서드를 미들웨어라고 하며, 미들웨어 구성 요소라고 부르기도 합니다. 요청 파이프라인의 각 미들웨어 구성 요소는 파이프라인의 그 다음 구성 요소를 호출하거나 파이프라인을 단락(short-circuiting)하는 역할을 담당합니다. 미들웨어가 단락(short-circuit)되는 경우 미들웨어에서 더는 요청을 처리하지 못하도록 하기 때문에 이를 터미널 미들웨어라고 합니다.

HTTP 핸들러 및 모듈을 ASP.NET Core 미들웨어로 마이그레이션에서는 ASP.NET Core와 ASP.NET 4.x 간의 요청 파이프라인 차이점을 설명하고 더 많은 미들웨어 샘플을 제공합니다.

미들웨어 코드 분석

ASP.NET Core에는 애플리케이션 코드의 품질을 검사하는 많은 컴파일러 플랫폼 분석기가 포함되어 있습니다. 자세한 내용은 ASP.NET Core 앱의 코드 분석을 참조하세요.

WebApplication으로 미들웨어 파이프라인 만들기

ASP.NET Core 요청 파이프라인은 하나씩 차례로 호출되는 요청 대리자 시퀀스로 구성됩니다. 다음 다이어그램은 그 개념을 보여줍니다. 실행 스레드는 검은색 화살표를 따릅니다.

요청이 도착하고, 세 개의 미들웨어를 통해 처리하고, 앱에서 응답이 나가는 것을 보여주는 요청 처리 패턴입니다. 각 미들웨어는 해당 논리를 실행하고 next() 문에서 다음 미들웨어로 요청을 전달합니다. 세 번째 미들웨어가 요청을 처리한 후, 클라이언트에 대한 응답으로 앱을 떠나기 전에 해당 next() 문 이후 추가 처리에 대해 반대 순서로 이전의 미들웨어 두 개를 통해 요청을 다시 전달합니다.

각 대리자는 다음 대리자 전과 후에 작업을 수행할 수 있습니다. 예외 처리 대리자는 파이프라인의 이후 단계에서 발생하는 예외를 잡을 수 있도록 파이프라인의 초기에 호출되어야 합니다.

가장 간단한 가능한 ASP.NET Core 앱은 모든 요청을 처리하는 단일 요청 대리자를 설정합니다. 이 경우 실제 요청 파이프라인은 포함되지 않습니다. 대신, 단일 익명 함수가 모든 HTTP 요청에 대한 응답에 호출됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Use를 사용하여 여러 요청 대리자를 연결합니다. next 매개 변수는 파이프라인의 다음 대리자를 나타냅니다. next 매개 변수를 호출하지 않고 파이프라인을 단락(short-circuit)할 수 있습니다. 다음 예제의 설명처럼, 일반적으로 next 대리자 전과 후 모두에서 작업을 수행할 수 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

요청 파이프라인 단락

대리자가 다음 대리자에 요청을 전달하지 않을 때 이를 요청 파이프라인을 단락(short-circuiting)한다고 합니다. 단락(short-circuiting)은 불필요한 작업을 방지하기 때문에 종종 바람직합니다. 예를 들어 정적 파일 미들웨어는 정적 파일에 대한 요청을 처리하고 파이프라인의 단락을 통해 rest 터미널 미들웨어 역할을 할 수 있습니다. 추가 처리를 종료하는 미들웨어 전에 파이프라인에 추가된 미들웨어는 next.Invoke 문 이후의 코드를 계속 처리합니다. 그러나 이미 전송된 응답에 쓰려고 시도하는 것에 대한 다음 경고를 참조하세요.

Warning

응답이 클라이언트에 전송된 도중이나 후에는 호출 next.Invoke 하지 마세요. HttpResponse 시작되면 변경 내용으로 인해 예외가 발생합니다. 예를 들어 헤더 및 상태 코드를 설정하면 응답이 시작된 후 예외 가 throw됩니다. next를 호출한 후 응답 본문에 작성할 경우:

  • 명시된 Content-Length것보다 더 많이 쓰는 것과 같은 프로토콜 위반이 발생할 수 있습니다.
  • CSS 파일에 HTML 바닥글을 쓰는 등 본문 형식이 손상될 수 있습니다.

HasStarted는 헤더가 이미 전송됐는지 또는 본문이 이미 작성됐는지 여부를 나타내는 유용한 힌트를 제공해줍니다.

자세한 내용은 라우팅 후 단락 미들웨어를 참조 하세요.

Run 대리자

Run 대리자는 next 매개 변수를 받지 않습니다. 첫 번째 Run 대리자는 항상 터미널이며 파이프라인을 종료합니다. Run이 규칙입니다. 일부 미들웨어 구성 요소는 파이프라인의 끝에서 실행되는 Run[Middleware] 메서드를 노출할 수 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

영어 이외의 언어로 번역된 코드 주석을 보려면 이 GitHub 토론 이슈에서 알려주세요.

위 예제에서 Run 대리자는 응답에 "Hello from 2nd delegate."를 쓴 다음 파이프라인을 종료합니다. Run 대리자 뒤에 추가된 다른 Use 또는 Run 대리자는 호출되지 않습니다.

컨텍스트를 next로 전달해야 하는 app.Use 오버로드 선호

할당하지 않는 app.Use 확장 메서드:

  • 컨텍스트를 next로 전달해야 합니다.
  • 다른 오버로드를 사용할 때 필요한 두 개의 내부 요청당 할당을 저장합니다.

자세한 내용은 해당 GitHub 이슈를 참조하세요.

미들웨어 순서

다음 다이어그램은 ASP.NET Core MVC 및 Razor Pages 앱의 전체 요청 처리 파이프라인을 보여 줍니다. 일반적인 앱에서 기존 미들웨어의 순서가 지정되는 방식과 사용자 지정 미들웨어가 추가되는 위치를 볼 수 있습니다. 사용자는 원하는 대로 기존 미들웨어의 순서를 바꾸거나 시나리오의 필요에 따라 새 사용자 지정 미들웨어를 주입할 수 있습니다.

ASP.NET Core 미들웨어 파이프라인

앞에 나온 다이어그램의 엔드포인트 미들웨어는 해당 앱 형식(MVC 또는 Razor Pages)에 따라 필터 파이프라인을 실행합니다.

위 다이어그램의 라우팅 미들웨어는 정적 파일 다음에 표시됩니다. 이는 app.UseRouting을 명시적으로 호출하여 프로젝트 템플릿이 구현되는 순서입니다. app.UseRouting을 호출하지 않으면 라우팅 미들웨어는 기본적으로 파이프라인의 시작 부분에서 실행됩니다. 자세한 내용은 라우팅을 참조하세요.

ASP.NET Core 필터 파이프라인

미들웨어 구성 요소가 파일에 추가 Program.cs 되는 순서는 요청 시 미들웨어 구성 요소가 호출되는 순서와 응답의 역순을 정의합니다. 순서는 보안, 성능 및 기능에 중요합니다.

다음 강조 표시된 코드는 Program.cs 일반적인 권장 순서로 보안 관련 미들웨어 구성 요소를 추가합니다.

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

위의 코드에서

  • 개별 사용자 계정을 사용하여 새 웹앱을 만들 때 추가되지 않는 미들웨어는 주석 처리됩니다.
  • 모든 미들웨어가 정확한 순서로 표시되는 것은 아닙니다. 예:
    • UseCors, UseAuthentication, UseAuthorization은 표시된 순서로 표시되어야 합니다.
    • 현재 UseCorsUseResponseCaching보다 먼저 표시되어야 합니다. 이 요구 사항은 GitHub 이슈 dotnet/aspnetcore #23218에 설명되어 있습니다.
    • UseRequestLocalization 는 요청 문화권을 확인할 수 있는 미들웨어 앞에 나타나야 합니다. 예를 들면 app.UseStaticFiles()다음과 같습니다.
    • UseRateLimiter 는 속도 제한 엔드포인트 특정 API를 사용하는 경우 호출 UseRouting 해야 합니다. 예를 들어 특성을 사용하는 UseRateLimiter 경우 [EnableRateLimiting] 다음을 UseRouting호출해야 합니다. 전역 리미터 UseRateLimiter 만 호출하는 경우 이전에 UseRouting호출할 수 있습니다.

일부 시나리오의 경우 미들웨어는 다른 순서를 갖습니다. 예를 들어 캐싱 및 압축 순서는 시나리오마다 다르며 유효한 순서가 여러 개 있습니다. 예시:

app.UseResponseCaching();
app.UseResponseCompression();

위의 코드를 사용하면 압축된 응답을 캐싱하여 CPU 사용량을 줄일 수 있지만, Gzip 또는 Brotli와 같은 다른 압축 알고리즘을 사용하여 리소스의 여러 표현을 캐싱할 수도 있습니다.

다음 순서는 정적 파일을 결합하여 압축된 정적 파일 캐싱을 허용합니다.

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

다음 Program.cs 코드는 일반적인 앱 시나리오에 대한 미들웨어 구성 요소를 추가합니다.

  1. 예외/오류 처리
    • 개발 환경에서 앱이 실행되는 경우:
      • 개발자 예외 페이지 미들웨어(UseDeveloperExceptionPage)가 앱 런타임 오류를 보고합니다.
      • 데이터베이스 오류 페이지 미들웨어(UseDatabaseErrorPage)가 데이터베이스 런타임 오류를 보고합니다.
    • 앱이 프로덕션 환경에서 실행되는 경우:
      • 예외 처리기 미들웨어(UseExceptionHandler)가 다음 미들웨어에서 던져진 예외를 잡습니다.
      • HTTP HSTS(엄격한 전송 보안 프로토콜) 미들웨어(UseHsts)가 Strict-Transport-Security 헤더를 추가합니다.
  2. HTTPS 리디렉션 미들웨어(UseHttpsRedirection)가 HTTP 요청을 HTTPS로 리디렉션합니다.
  3. 정적 파일 미들웨어(UseStaticFiles)가 정적 파일을 반환하고 추가 요청 처리를 단락합니다.
  4. Cookie 정책 미들웨어(UseCookiePolicy)가 앱이 EU GDPR(일반 데이터 보호 규정)을 준수하도록 만듭니다.
  5. 요청을 라우팅하도록 미들웨어(UseRouting) 라우팅.
  6. 인증 미들웨어(UseAuthentication)가 보안 리소스에 대한 액세스가 허용되기 전에 사용자 인증을 시도합니다.
  7. 권한 부여 미들웨어(UseAuthorization)는 사용자에게 보안 리소스에 액세스할 수 있는 권한을 부여합니다.
  8. 세션 미들웨어(UseSession)가 세션 상태를 설정 및 유지합니다. 앱이 세션 상태를 사용하는 경우에는 Cookie 정책 미들웨어 이후 및 MVC 미들웨어 이전에 세션 미들웨어를 호출하세요.
  9. 엔드포인트 라우팅 미들웨어(MapRazorPages를 포함하는 UseEndpoints)를 사용하여 요청 파이프라인에 Razor Pages 엔드포인트를 추가합니다.
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

앞의 예제 코드에서 각 미들웨어 확장 메서드는 Microsoft.AspNetCore.Builder 네임스페이스를 통해 WebApplicationBuilder에 표시됩니다.

UseExceptionHandler는 파이프라인에 처음으로 추가된 미들웨어 구성 요소입니다. 따라서 예외 처리기 미들웨어는 후속 호출에서 발생하는 모든 예외를 catch 합니다.

정적 파일 미들웨어는 파이프라인 초기에 호출되므로 요청을 처리하고 나머지 구성 요소를 통과하지 않고 단락(short-circuit)할 수 있습니다. 정적 파일 미들웨어는 권한 부여 검사를 제공하지 않습니다. wwwroot에 있는 파일을 포함한 정적 파일 미들웨어에서 제공하는 모든 파일은 공개적으로 사용할 수 있습니다. 정적 파일을 보호하는 방법은 ASP.NET Core의 정적 파일을 참조하세요.

요청이 정적 파일 미들웨어에서 처리되지 않는 경우 인증을 수행하는 인증 미들웨어(UseAuthentication)로 전달됩니다. 인증은 인증되지 않은 요청을 단락(short-circuit)하지 않습니다. 인증 미들웨어가 요청을 인증하지만, MVC가 특정 Razor Page 또는 컨트롤러 및 작업을 선택한 후에만 권한 부여(및 거부)가 발생합니다.

다음 예제는 정적 파일에 대한 요청이 응답 압축 미들웨어 전에 정적 파일 미들웨어에서 처리되는 미들웨어 순서를 설명합니다. 정적 파일은 이 미들웨어 순서를 사용하여 압축되지 않습니다. Razor Pages 응답을 압축할 수 있습니다.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

단일 페이지 애플리케이션에 대한 자세한 내용은 ASP.NET Core의 SPA(단일 페이지 앱) 개요를 참조 하세요.

UseCors 및 UseStaticFiles 순서

UseCorsUseStaticFiles 호출의 순서는 앱에 따라 달라집니다. 자세한 내용은 UseCors 및 UseStaticFiles 순서를 참조하세요.

전달된 헤더 미들웨어 순서

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

미들웨어 파이프라인 분기

Map 확장은 파이프라인 분기에 규칙으로 사용됩니다. Map은 지정된 요청 경로의 일치를 기반으로 요청 파이프라인을 분기합니다. 요청 경로가 지정된 경로로 시작하는 경우 분기가 실행됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

다음 표는 위의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/map1 Map Test 1
localhost:1234/map2 Map Test 2
localhost:1234/map3 Hello from non-Map delegate.

Map이 사용되는 경우 일치하는 경로 세그먼트는 HttpRequest.Path에서 제거되고 각 요청에 대해 HttpRequest.PathBase에 추가됩니다.

Map은 중첩을 지원합니다. 예를 들면 다음과 같습니다.

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map은 여러 세그먼트를 한 번에 일치시킬 수도 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/seg1", HandleMultiSeg);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen은 지정된 조건자의 결과를 기반으로 요청 파이프라인을 분기합니다. Func<HttpContext, bool> 형식의 조건자는 파이프라인의 새 분기에 요청을 매핑하는 데 사용될 수 있습니다. 다음 예제에서 조건자는 쿼리 문자열 변수 branch의 존재를 검색하는 데 사용됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

다음 표는 앞의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen도 지정된 조건자의 결과를 기준으로 요청 파이프라인을 분기합니다. MapWhen과 달리, 이 분기는 단락을 수행하거나 터미널 미들웨어를 포함하지 않는 경우 기본 파이프라인에 다시 연결됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

위의 예제에서 Hello from non-Map delegate. 응답은 모든 요청에 대해 기록됩니다. 요청에 쿼리 문자열 변수 branch가 포함되어 있으면, 기본 파이프라인이 다시 연결되기 전에 변수 값이 기록됩니다.

기본 제공 미들웨어

ASP.NET Core는 다음과 같은 미들웨어 구성 요소가 함께 제공됩니다. 순서 열은 요청 처리 파이프라인에서 미들웨어의 배치, 미들웨어가 요청 처리를 종료할 수 있는 조건에 대한 정보를 제공합니다. 미들웨어가 요청 처리 파이프라인을 단락(short-circuit)하고 후속 미들웨어가 더는 요청을 처리하지 못하도록 하는 경우 이를 터미널 미들웨어라고 합니다. 단락에 대한 자세한 내용은 WebApplication사용하여 미들웨어 파이프라인 만들기 섹션을 참조하세요.

미들웨어 설명 순서
인증 인증 지원을 제공합니다. HttpContext.User가 필요하기 전에. OAuth 콜백에 대한 터미널.
Authorization 권한 부여 지원을 제공합니다. 인증 미들웨어 바로 뒤에 있습니다.
Cookie 정책 개인 정보 저장과 관련한 사용자의 동의를 추적하고 cookie 필드(예: secureSameSite)에 대해 최소한의 표준을 적용합니다. 쿠키를 발행하는 미들웨어 전에. 예: 인증, 세션, MVC(TempData).
CORS 원본 간 리소스 공유를 구성합니다. CORS를 사용하는 구성 요소 이전. 현재 UseCors이 버그로 인해 UseResponseCaching보다 먼저 사용됩니다.
DeveloperExceptionPage 개발 환경에서만 사용하기 위한 오류 정보가 포함된 페이지를 생성합니다. 오류를 생성하는 구성 요소 이전. 프로젝트 템플릿은 환경이 개발일 때 이 미들웨어를 파이프라인의 첫 번째 미들웨어로 자동으로 등록합니다.
진단 개발자 예외 페이지, 예외 처리, 상태 코드 페이지 및 새 앱에 대한 기본 웹 페이지를 제공하는 몇 가지 개별 미들웨어. 오류를 생성하는 구성 요소 이전. 예외가 발생하거나 새 앱의 기본 웹 페이지를 처리하는 터미널입니다.
전달된 헤더 프록시된 헤더를 현재 요청에 전달합니다. 업데이트된 필드를 사용하는 구성 요소 전에. 예: 체계, 호스트, 클라이언트 IP, 메서드.
상태 확인 ASP.NET Core 앱 및 그 종속성(데이터베이스 가용성 등)의 상태를 검사합니다. 요청이 상태 검사 엔드포인트와 일치하는 경우 마지막입니다.
헤더 전파 들어오는 요청에서 나가는 HTTP 클라이언트 요청으로 HTTP 헤더를 전파합니다.
HTTP 로깅 HTTP 요청 및 응답을 로그합니다. 미들웨어 파이프라인의 시작 부분에서.
HTTP 메서드 재정의 들어오는 POST 요청이 메서드를 재정의하도록 허용합니다. 업데이트된 메서드를 사용하는 구성 요소 앞입니다.
HTTPS 리디렉션 모든 HTTP 요청을 HTTPS로 리디렉션합니다. URL을 사용하는 구성 요소 이전.
HSTS(HTTP 엄격한 전송 보안) 특별한 응답 헤더를 추가하는 보안 향상 미들웨어입니다. 응답이 전송되기 이전, 요청을 수정하는 구성 요소 이후에. 예: 전달된 헤더, URL 재작성.
MVC MVC/Razor Pages를 사용하여 요청을 처리합니다. 요청이 경로와 일치하는 경우 터미널입니다.
OWIN OWIN 기반 앱, 서버 및 미들웨어와 상호 운용됩니다. OWIN 미들웨어가 요청을 완벽하게 처리하는 경우 터미널입니다.
출력 캐싱 구성에 따라 응답 캐싱을 지원합니다. 캐싱이 필요한 구성 요소 이전. UseRoutingUseOutputCaching 앞에 와야 합니다. UseCORSUseOutputCaching 앞에 와야 합니다.
응답 캐싱 응답 캐시에 대한 지원을 제공합니다. 이렇게 하려면 클라이언트 참여가 필요합니다. 전체 서버 제어에 출력 캐싱을 사용합니다. 캐싱이 필요한 구성 요소 이전. UseCORSUseResponseCaching 앞에 와야 합니다. 브라우저는 일반적으로 캐싱을 방지하는 요청 헤더를 설정하기 때문에 Razor Pages와 같은 UI 앱에는 일반적으로 도움이 되지 않습니다. 출력 캐싱은 UI 앱의 이점을 제공합니다.
요청 압축 해제 요청 압축 해제를 지원합니다. 요청 본문을 읽는 구성 요소 이전
응답 압축 응답 압축에 대한 지원을 제공합니다. 압축이 필요한 구성 요소 이전.
요청 지역화 지역화 지원을 제공합니다. 지역화 구분 구성 요소 이전. RouteDataRequestCultureProvider를 사용할 경우 라우팅 미들웨어 뒤에 표시되어야 합니다.
요청 시간 제한 요청 시간 제한, 전역 및 엔드포인트당 구성을 지원합니다. UseRequestTimeoutsUseExceptionHandler는 다음 , UseDeveloperExceptionPageUseRouting.
엔드포인트 라우팅 요청 경로를 정의하고 제한합니다. 경로 일치에 대한 터미널.
스파 SPA(단일 페이지 애플리케이션)의 기반 페이지를 반환하여 이 시점부터 미들웨어 체인의 모든 요청을 처리합니다. 정적 파일, MVC 작업 등을 처리하는 다른 미들웨어가 우선할 수 있도록 이 미들웨어는 체인에서 늦게 배치되어야 합니다.
세션 사용자 세션 관리에 대한 지원을 제공합니다. 세션이 필요한 구성 요소 이전.
정적 파일 정적 파일 및 디렉터리 검색 처리에 대한 지원을 제공합니다. 요청이 파일과 일치하는 경우 터미널입니다.
URL 재작성 URL 재작성 및 요청 리디렉션에 대한 지원을 제공합니다. URL을 사용하는 구성 요소 이전.
W3CLogging W3C 확장 로그 파일 형식으로 서버 액세스 로그를 생성합니다. 미들웨어 파이프라인의 시작 부분에서.
WebSocket WebSocket 프로토콜을 활성화합니다. WebSocket 요청을 수락하는 데 필요한 구성 요소 이전.

추가 리소스

작성자: Rick AndersonSteve Smith

미들웨어는 요청 및 응답을 처리하는 앱 파이프라인으로 어셈블리되는 소프트웨어입니다. 각 구성 요소:

  • 요청을 파이프라인의 다음 구성 요소로 전달할지 여부를 선택합니다.
  • 파이프라인의 다음 구성 요소 전과 후에 작업을 수행할 수 있습니다.

요청 대리자는 요청 파이프라인을 빌드하는 데 사용됩니다. 요청 대리자는 각 HTTP 요청을 처리합니다.

요청 대리자는 Run, MapUse 확장 메서드를 사용하여 구성됩니다. 개별 요청 대리자는 무명 메서드(인라인 미들웨어라고 함)로 인라인에서 지정되거나 다시 사용할 수 있는 클래스에서 정의될 수 있습니다. 이러한 다시 사용할 수 있는 클래스 및 인라인 무명 메서드를 미들웨어라고 하며, 미들웨어 구성 요소라고 부르기도 합니다. 요청 파이프라인의 각 미들웨어 구성 요소는 파이프라인의 그 다음 구성 요소를 호출하거나 파이프라인을 단락(short-circuiting)하는 역할을 담당합니다. 미들웨어가 단락(short-circuit)되는 경우 미들웨어에서 더는 요청을 처리하지 못하도록 하기 때문에 이를 터미널 미들웨어라고 합니다.

HTTP 핸들러 및 모듈을 ASP.NET Core 미들웨어로 마이그레이션에서는 ASP.NET Core와 ASP.NET 4.x 간의 요청 파이프라인 차이점을 설명하고 더 많은 미들웨어 샘플을 제공합니다.

미들웨어 코드 분석

ASP.NET Core에는 애플리케이션 코드의 품질을 검사하는 많은 컴파일러 플랫폼 분석기가 포함되어 있습니다. 자세한 내용은 ASP.NET Core 앱의 코드 분석을 참조하세요.

WebApplication으로 미들웨어 파이프라인 만들기

ASP.NET Core 요청 파이프라인은 하나씩 차례로 호출되는 요청 대리자 시퀀스로 구성됩니다. 다음 다이어그램은 그 개념을 보여줍니다. 실행 스레드는 검은색 화살표를 따릅니다.

요청이 도착하고, 세 개의 미들웨어를 통해 처리하고, 앱에서 응답이 나가는 것을 보여주는 요청 처리 패턴입니다. 각 미들웨어는 해당 논리를 실행하고 next() 문에서 다음 미들웨어로 요청을 전달합니다. 세 번째 미들웨어가 요청을 처리한 후, 클라이언트에 대한 응답으로 앱을 떠나기 전에 해당 next() 문 이후 추가 처리에 대해 반대 순서로 이전의 미들웨어 두 개를 통해 요청을 다시 전달합니다.

각 대리자는 다음 대리자 전과 후에 작업을 수행할 수 있습니다. 예외 처리 대리자는 파이프라인의 이후 단계에서 발생하는 예외를 잡을 수 있도록 파이프라인의 초기에 호출되어야 합니다.

가장 간단한 가능한 ASP.NET Core 앱은 모든 요청을 처리하는 단일 요청 대리자를 설정합니다. 이 경우 실제 요청 파이프라인은 포함되지 않습니다. 대신, 단일 익명 함수가 모든 HTTP 요청에 대한 응답에 호출됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Use를 사용하여 여러 요청 대리자를 연결합니다. next 매개 변수는 파이프라인의 다음 대리자를 나타냅니다. next 매개 변수를 호출하지 않고 파이프라인을 단락(short-circuit)할 수 있습니다. 다음 예제의 설명처럼, 일반적으로 next 대리자 전과 후 모두에서 작업을 수행할 수 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

대리자가 다음 대리자에 요청을 전달하지 않을 때 이를 요청 파이프라인을 단락(short-circuiting)한다고 합니다. 단락(short-circuiting)은 불필요한 작업을 방지하기 때문에 종종 바람직합니다. 예를 들어 정적 파일 미들웨어는 정적 파일에 대한 요청을 처리하고 파이프라인의 단락을 통해 rest 터미널 미들웨어 역할을 할 수 있습니다. 추가 처리를 종료하는 미들웨어 전에 파이프라인에 추가된 미들웨어는 next.Invoke 문 이후의 코드를 계속 처리합니다. 그러나 이미 전송된 응답에 쓰려고 시도하는 것에 대한 다음 경고를 참조하세요.

Warning

클라이언트에 응답을 전송한 후에 next.Invoke를 호출하지 마십시오. 응답이 시작된 후 HttpResponse로 변경하면 예외를 던집니다. 예를 들어 헤더 및 상태 코드를 설정하면 예외를 throw합니다. next를 호출한 후 응답 본문에 작성할 경우:

  • 프로토콜 위반이 발생할 수 있습니다. 예를 들어, 명시된 Content-Length보다 긴 내용이 작성될 수 있습니다.
  • 본문 형식을 손상시킬 수 있습니다. 예를 들어, CSS 파일에 HTML 바닥글을 작성할 수 있습니다.

HasStarted는 헤더가 이미 전송됐는지 또는 본문이 이미 작성됐는지 여부를 나타내는 유용한 힌트를 제공해줍니다.

Run 대리자는 next 매개 변수를 받지 않습니다. 첫 번째 Run 대리자는 항상 터미널이며 파이프라인을 종료합니다. Run이 규칙입니다. 일부 미들웨어 구성 요소는 파이프라인의 끝에서 실행되는 Run[Middleware] 메서드를 노출할 수 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

영어 이외의 언어로 번역된 코드 주석을 보려면 이 GitHub 토론 이슈에서 알려주세요.

위 예제에서 Run 대리자는 응답에 "Hello from 2nd delegate."를 쓴 다음 파이프라인을 종료합니다. Run 대리자 뒤에 추가된 다른 Use 또는 Run 대리자는 호출되지 않습니다.

컨텍스트를 next로 전달해야 하는 app.Use 오버로드 선호

할당하지 않는 app.Use 확장 메서드:

  • 컨텍스트를 next로 전달해야 합니다.
  • 다른 오버로드를 사용할 때 필요한 두 개의 내부 요청당 할당을 저장합니다.

자세한 내용은 해당 GitHub 이슈를 참조하세요.

미들웨어 순서

다음 다이어그램은 ASP.NET Core MVC 및 Razor Pages 앱의 전체 요청 처리 파이프라인을 보여 줍니다. 일반적인 앱에서 기존 미들웨어의 순서가 지정되는 방식과 사용자 지정 미들웨어가 추가되는 위치를 볼 수 있습니다. 사용자는 원하는 대로 기존 미들웨어의 순서를 바꾸거나 시나리오의 필요에 따라 새 사용자 지정 미들웨어를 주입할 수 있습니다.

ASP.NET Core 미들웨어 파이프라인

앞에 나온 다이어그램의 엔드포인트 미들웨어는 해당 앱 형식(MVC 또는 Razor Pages)에 따라 필터 파이프라인을 실행합니다.

위 다이어그램의 라우팅 미들웨어는 정적 파일 다음에 표시됩니다. 이는 app.UseRouting을 명시적으로 호출하여 프로젝트 템플릿이 구현되는 순서입니다. app.UseRouting을 호출하지 않으면 라우팅 미들웨어는 기본적으로 파이프라인의 시작 부분에서 실행됩니다. 자세한 내용은 라우팅을 참조하세요.

ASP.NET Core 필터 파이프라인

미들웨어 구성 요소가 파일에 추가 Program.cs 되는 순서는 요청 시 미들웨어 구성 요소가 호출되는 순서와 응답의 역순을 정의합니다. 순서는 보안, 성능 및 기능에 중요합니다.

다음 강조 표시된 코드는 Program.cs 일반적인 권장 순서로 보안 관련 미들웨어 구성 요소를 추가합니다.

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebMiddleware.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRateLimiter();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapDefaultControllerRoute();

app.Run();

위의 코드에서

  • 개별 사용자 계정을 사용하여 새 웹앱을 만들 때 추가되지 않는 미들웨어는 주석 처리됩니다.
  • 모든 미들웨어가 정확한 순서로 표시되는 것은 아닙니다. 예:
    • UseCors, UseAuthentication, UseAuthorization은 표시된 순서로 표시되어야 합니다.
    • 현재 UseCorsUseResponseCaching보다 먼저 표시되어야 합니다. 이 요구 사항은 GitHub 이슈 dotnet/aspnetcore #23218에 설명되어 있습니다.
    • UseRequestLocalization 는 요청 문화권을 확인할 수 있는 미들웨어 앞에 나타나야 합니다. 예를 들면 app.UseStaticFiles()다음과 같습니다.
    • UseRateLimiter 는 속도 제한 엔드포인트 특정 API를 사용하는 경우 호출 UseRouting 해야 합니다. 예를 들어 특성을 사용하는 UseRateLimiter 경우 [EnableRateLimiting] 다음을 UseRouting호출해야 합니다. 전역 리미터 UseRateLimiter 만 호출하는 경우 이전에 UseRouting호출할 수 있습니다.

일부 시나리오의 경우 미들웨어는 다른 순서를 갖습니다. 예를 들어 캐싱 및 압축 순서는 시나리오마다 다르며 유효한 순서가 여러 개 있습니다. 예시:

app.UseResponseCaching();
app.UseResponseCompression();

위의 코드를 사용하면 압축된 응답을 캐싱하여 CPU 사용량을 줄일 수 있지만, Gzip 또는 Brotli와 같은 다른 압축 알고리즘을 사용하여 리소스의 여러 표현을 캐싱할 수도 있습니다.

다음 순서는 정적 파일을 결합하여 압축된 정적 파일 캐싱을 허용합니다.

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

다음 Program.cs 코드는 일반적인 앱 시나리오에 대한 미들웨어 구성 요소를 추가합니다.

  1. 예외/오류 처리
    • 개발 환경에서 앱이 실행되는 경우:
      • 개발자 예외 페이지 미들웨어(UseDeveloperExceptionPage)가 앱 런타임 오류를 보고합니다.
      • 데이터베이스 오류 페이지 미들웨어(UseDatabaseErrorPage)가 데이터베이스 런타임 오류를 보고합니다.
    • 앱이 프로덕션 환경에서 실행되는 경우:
      • 예외 처리기 미들웨어(UseExceptionHandler)가 다음 미들웨어에서 던져진 예외를 잡습니다.
      • HTTP HSTS(엄격한 전송 보안 프로토콜) 미들웨어(UseHsts)가 Strict-Transport-Security 헤더를 추가합니다.
  2. HTTPS 리디렉션 미들웨어(UseHttpsRedirection)가 HTTP 요청을 HTTPS로 리디렉션합니다.
  3. 정적 파일 미들웨어(UseStaticFiles)가 정적 파일을 반환하고 추가 요청 처리를 단락합니다.
  4. Cookie 정책 미들웨어(UseCookiePolicy)가 앱이 EU GDPR(일반 데이터 보호 규정)을 준수하도록 만듭니다.
  5. 요청을 라우팅하도록 미들웨어(UseRouting) 라우팅.
  6. 인증 미들웨어(UseAuthentication)가 보안 리소스에 대한 액세스가 허용되기 전에 사용자 인증을 시도합니다.
  7. 권한 부여 미들웨어(UseAuthorization)는 사용자에게 보안 리소스에 액세스할 수 있는 권한을 부여합니다.
  8. 세션 미들웨어(UseSession)가 세션 상태를 설정 및 유지합니다. 앱이 세션 상태를 사용하는 경우에는 Cookie 정책 미들웨어 이후 및 MVC 미들웨어 이전에 세션 미들웨어를 호출하세요.
  9. 엔드포인트 라우팅 미들웨어(MapRazorPages를 포함하는 UseEndpoints)를 사용하여 요청 파이프라인에 Razor Pages 엔드포인트를 추가합니다.
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

앞의 예제 코드에서 각 미들웨어 확장 메서드는 Microsoft.AspNetCore.Builder 네임스페이스를 통해 WebApplicationBuilder에 표시됩니다.

UseExceptionHandler는 파이프라인에 처음으로 추가된 미들웨어 구성 요소입니다. 따라서 예외 처리기 미들웨어는 후속 호출에서 발생하는 모든 예외를 catch 합니다.

정적 파일 미들웨어는 파이프라인 초기에 호출되므로 요청을 처리하고 나머지 구성 요소를 통과하지 않고 단락(short-circuit)할 수 있습니다. 정적 파일 미들웨어는 권한 부여 검사를 제공하지 않습니다. wwwroot에 있는 파일을 포함한 정적 파일 미들웨어에서 제공하는 모든 파일은 공개적으로 사용할 수 있습니다. 정적 파일을 보호하는 방법은 ASP.NET Core의 정적 파일을 참조하세요.

요청이 정적 파일 미들웨어에서 처리되지 않는 경우 인증을 수행하는 인증 미들웨어(UseAuthentication)로 전달됩니다. 인증은 인증되지 않은 요청을 단락(short-circuit)하지 않습니다. 인증 미들웨어가 요청을 인증하지만, MVC가 특정 Razor Page 또는 컨트롤러 및 작업을 선택한 후에만 권한 부여(및 거부)가 발생합니다.

다음 예제는 정적 파일에 대한 요청이 응답 압축 미들웨어 전에 정적 파일 미들웨어에서 처리되는 미들웨어 순서를 설명합니다. 정적 파일은 이 미들웨어 순서를 사용하여 압축되지 않습니다. Razor Pages 응답을 압축할 수 있습니다.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

단일 페이지 애플리케이션에 대한 자세한 내용은 ReactAngular 프로젝트 템플릿 관련 가이드를 참조하세요.

UseCors 및 UseStaticFiles 순서

UseCorsUseStaticFiles 호출의 순서는 앱에 따라 달라집니다. 자세한 내용은 UseCors 및 UseStaticFiles 순서를 참조하세요.

전달된 헤더 미들웨어 순서

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

미들웨어 파이프라인 분기

Map 확장은 파이프라인 분기에 규칙으로 사용됩니다. Map은 지정된 요청 경로의 일치를 기반으로 요청 파이프라인을 분기합니다. 요청 경로가 지정된 경로로 시작하는 경우 분기가 실행됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

다음 표는 위의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/map1 Map Test 1
localhost:1234/map2 Map Test 2
localhost:1234/map3 Hello from non-Map delegate.

Map이 사용되는 경우 일치하는 경로 세그먼트는 HttpRequest.Path에서 제거되고 각 요청에 대해 HttpRequest.PathBase에 추가됩니다.

Map은 중첩을 지원합니다. 예를 들면 다음과 같습니다.

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map은 여러 세그먼트를 한 번에 일치시킬 수도 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/seg1", HandleMultiSeg);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen은 지정된 조건자의 결과를 기반으로 요청 파이프라인을 분기합니다. Func<HttpContext, bool> 형식의 조건자는 파이프라인의 새 분기에 요청을 매핑하는 데 사용될 수 있습니다. 다음 예제에서 조건자는 쿼리 문자열 변수 branch의 존재를 검색하는 데 사용됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

다음 표는 앞의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen도 지정된 조건자의 결과를 기준으로 요청 파이프라인을 분기합니다. MapWhen과 달리, 이 분기는 단락을 수행하거나 터미널 미들웨어를 포함하지 않는 경우 기본 파이프라인에 다시 연결됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

위의 예제에서 Hello from non-Map delegate. 응답은 모든 요청에 대해 기록됩니다. 요청에 쿼리 문자열 변수 branch가 포함되어 있으면, 기본 파이프라인이 다시 연결되기 전에 변수 값이 기록됩니다.

기본 제공 미들웨어

ASP.NET Core는 다음과 같은 미들웨어 구성 요소가 함께 제공됩니다. 순서 열은 요청 처리 파이프라인에서 미들웨어의 배치, 미들웨어가 요청 처리를 종료할 수 있는 조건에 대한 정보를 제공합니다. 미들웨어가 요청 처리 파이프라인을 단락(short-circuit)하고 후속 미들웨어가 더는 요청을 처리하지 못하도록 하는 경우 이를 터미널 미들웨어라고 합니다. 단락에 대한 자세한 내용은 WebApplication사용하여 미들웨어 파이프라인 만들기 섹션을 참조하세요.

미들웨어 설명 순서
인증 인증 지원을 제공합니다. HttpContext.User가 필요하기 전에. OAuth 콜백에 대한 터미널.
Authorization 권한 부여 지원을 제공합니다. 인증 미들웨어 바로 뒤에 있습니다.
Cookie 정책 개인 정보 저장과 관련한 사용자의 동의를 추적하고 cookie 필드(예: secureSameSite)에 대해 최소한의 표준을 적용합니다. 쿠키를 발행하는 미들웨어 전에. 예: 인증, 세션, MVC(TempData).
CORS 원본 간 리소스 공유를 구성합니다. CORS를 사용하는 구성 요소 이전. 현재 UseCors이 버그로 인해 UseResponseCaching보다 먼저 사용됩니다.
DeveloperExceptionPage 개발 환경에서만 사용하기 위한 오류 정보가 포함된 페이지를 생성합니다. 오류를 생성하는 구성 요소 이전. 프로젝트 템플릿은 환경이 개발일 때 이 미들웨어를 파이프라인의 첫 번째 미들웨어로 자동으로 등록합니다.
진단 개발자 예외 페이지, 예외 처리, 상태 코드 페이지 및 새 앱에 대한 기본 웹 페이지를 제공하는 몇 가지 개별 미들웨어. 오류를 생성하는 구성 요소 이전. 예외가 발생하거나 새 앱의 기본 웹 페이지를 처리하는 터미널입니다.
전달된 헤더 프록시된 헤더를 현재 요청에 전달합니다. 업데이트된 필드를 사용하는 구성 요소 전에. 예: 체계, 호스트, 클라이언트 IP, 메서드.
상태 확인 ASP.NET Core 앱 및 그 종속성(데이터베이스 가용성 등)의 상태를 검사합니다. 요청이 상태 검사 엔드포인트와 일치하는 경우 마지막입니다.
헤더 전파 들어오는 요청에서 나가는 HTTP 클라이언트 요청으로 HTTP 헤더를 전파합니다.
HTTP 로깅 HTTP 요청 및 응답을 로그합니다. 미들웨어 파이프라인의 시작 부분에서.
HTTP 메서드 재정의 들어오는 POST 요청이 메서드를 재정의하도록 허용합니다. 업데이트된 메서드를 사용하는 구성 요소 앞입니다.
HTTPS 리디렉션 모든 HTTP 요청을 HTTPS로 리디렉션합니다. URL을 사용하는 구성 요소 이전.
HSTS(HTTP 엄격한 전송 보안) 특별한 응답 헤더를 추가하는 보안 향상 미들웨어입니다. 응답이 전송되기 이전, 요청을 수정하는 구성 요소 이후에. 예: 전달된 헤더, URL 재작성.
MVC MVC/Razor Pages를 사용하여 요청을 처리합니다. 요청이 경로와 일치하는 경우 터미널입니다.
OWIN OWIN 기반 앱, 서버 및 미들웨어와 상호 운용됩니다. OWIN 미들웨어가 요청을 완벽하게 처리하는 경우 터미널입니다.
출력 캐싱 구성에 따라 응답 캐싱을 지원합니다. 캐싱이 필요한 구성 요소 이전. UseRoutingUseOutputCaching 앞에 와야 합니다. UseCORSUseOutputCaching 앞에 와야 합니다.
응답 캐싱 응답 캐시에 대한 지원을 제공합니다. 이렇게 하려면 클라이언트 참여가 필요합니다. 전체 서버 제어에 출력 캐싱을 사용합니다. 캐싱이 필요한 구성 요소 이전. UseCORSUseResponseCaching 앞에 와야 합니다. 브라우저는 일반적으로 캐싱을 방지하는 요청 헤더를 설정하기 때문에 Razor Pages와 같은 UI 앱에는 일반적으로 도움이 되지 않습니다. 출력 캐싱은 UI 앱의 이점을 제공합니다.
요청 압축 해제 요청 압축 해제를 지원합니다. 요청 본문을 읽는 구성 요소 이전
응답 압축 응답 압축에 대한 지원을 제공합니다. 압축이 필요한 구성 요소 이전.
요청 지역화 지역화 지원을 제공합니다. 지역화 구분 구성 요소 이전. RouteDataRequestCultureProvider를 사용할 경우 라우팅 미들웨어 뒤에 표시되어야 합니다.
엔드포인트 라우팅 요청 경로를 정의하고 제한합니다. 경로 일치에 대한 터미널.
스파 SPA(단일 페이지 애플리케이션)의 기반 페이지를 반환하여 이 시점부터 미들웨어 체인의 모든 요청을 처리합니다. 정적 파일, MVC 작업 등을 처리하는 다른 미들웨어가 우선할 수 있도록 이 미들웨어는 체인에서 늦게 배치되어야 합니다.
세션 사용자 세션 관리에 대한 지원을 제공합니다. 세션이 필요한 구성 요소 이전.
정적 파일 정적 파일 및 디렉터리 검색 처리에 대한 지원을 제공합니다. 요청이 파일과 일치하는 경우 터미널입니다.
URL 재작성 URL 재작성 및 요청 리디렉션에 대한 지원을 제공합니다. URL을 사용하는 구성 요소 이전.
W3CLogging W3C 확장 로그 파일 형식으로 서버 액세스 로그를 생성합니다. 미들웨어 파이프라인의 시작 부분에서.
WebSocket WebSocket 프로토콜을 활성화합니다. WebSocket 요청을 수락하는 데 필요한 구성 요소 이전.

추가 리소스

작성자: Rick AndersonSteve Smith

미들웨어는 요청 및 응답을 처리하는 앱 파이프라인으로 어셈블리되는 소프트웨어입니다. 각 구성 요소:

  • 요청을 파이프라인의 다음 구성 요소로 전달할지 여부를 선택합니다.
  • 파이프라인의 다음 구성 요소 전과 후에 작업을 수행할 수 있습니다.

요청 대리자는 요청 파이프라인을 빌드하는 데 사용됩니다. 요청 대리자는 각 HTTP 요청을 처리합니다.

요청 대리자는 Run, MapUse 확장 메서드를 사용하여 구성됩니다. 개별 요청 대리자는 무명 메서드(인라인 미들웨어라고 함)로 인라인에서 지정되거나 다시 사용할 수 있는 클래스에서 정의될 수 있습니다. 이러한 다시 사용할 수 있는 클래스 및 인라인 무명 메서드를 미들웨어라고 하며, 미들웨어 구성 요소라고 부르기도 합니다. 요청 파이프라인의 각 미들웨어 구성 요소는 파이프라인의 그 다음 구성 요소를 호출하거나 파이프라인을 단락(short-circuiting)하는 역할을 담당합니다. 미들웨어가 단락(short-circuit)되는 경우 미들웨어에서 더는 요청을 처리하지 못하도록 하기 때문에 이를 터미널 미들웨어라고 합니다.

HTTP 핸들러 및 모듈을 ASP.NET Core 미들웨어로 마이그레이션에서는 ASP.NET Core와 ASP.NET 4.x 간의 요청 파이프라인 차이점을 설명하고 더 많은 미들웨어 샘플을 제공합니다.

미들웨어 코드 분석

ASP.NET Core에는 애플리케이션 코드의 품질을 검사하는 많은 컴파일러 플랫폼 분석기가 포함되어 있습니다. 자세한 내용은 ASP.NET Core 앱의 코드 분석을 참조하세요.

WebApplication으로 미들웨어 파이프라인 만들기

ASP.NET Core 요청 파이프라인은 하나씩 차례로 호출되는 요청 대리자 시퀀스로 구성됩니다. 다음 다이어그램은 그 개념을 보여줍니다. 실행 스레드는 검은색 화살표를 따릅니다.

요청이 도착하고, 세 개의 미들웨어를 통해 처리하고, 앱에서 응답이 나가는 것을 보여주는 요청 처리 패턴입니다. 각 미들웨어는 해당 논리를 실행하고 next() 문에서 다음 미들웨어로 요청을 전달합니다. 세 번째 미들웨어가 요청을 처리한 후, 클라이언트에 대한 응답으로 앱을 떠나기 전에 해당 next() 문 이후 추가 처리에 대해 반대 순서로 이전의 미들웨어 두 개를 통해 요청을 다시 전달합니다.

각 대리자는 다음 대리자 전과 후에 작업을 수행할 수 있습니다. 예외 처리 대리자는 파이프라인의 이후 단계에서 발생하는 예외를 잡을 수 있도록 파이프라인의 초기에 호출되어야 합니다.

가장 간단한 가능한 ASP.NET Core 앱은 모든 요청을 처리하는 단일 요청 대리자를 설정합니다. 이 경우 실제 요청 파이프라인은 포함되지 않습니다. 대신, 단일 익명 함수가 모든 HTTP 요청에 대한 응답에 호출됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello world!");
});

app.Run();

Use를 사용하여 여러 요청 대리자를 연결합니다. next 매개 변수는 파이프라인의 다음 대리자를 나타냅니다. next 매개 변수를 호출하지 않고 파이프라인을 단락(short-circuit)할 수 있습니다. 다음 예제의 설명처럼, 일반적으로 next 대리자 전과 후 모두에서 작업을 수행할 수 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

대리자가 다음 대리자에 요청을 전달하지 않을 때 이를 요청 파이프라인을 단락(short-circuiting)한다고 합니다. 단락(short-circuiting)은 불필요한 작업을 방지하기 때문에 종종 바람직합니다. 예를 들어 정적 파일 미들웨어는 정적 파일에 대한 요청을 처리하고 파이프라인의 단락을 통해 rest 터미널 미들웨어 역할을 할 수 있습니다. 추가 처리를 종료하는 미들웨어 전에 파이프라인에 추가된 미들웨어는 next.Invoke 문 이후의 코드를 계속 처리합니다. 그러나 이미 전송된 응답에 쓰려고 시도하는 것에 대한 다음 경고를 참조하세요.

Warning

클라이언트에 응답을 전송한 후에 next.Invoke를 호출하지 마십시오. 응답이 시작된 후 HttpResponse로 변경하면 예외를 던집니다. 예를 들어 헤더 및 상태 코드를 설정하면 예외를 throw합니다. next를 호출한 후 응답 본문에 작성할 경우:

  • 프로토콜 위반이 발생할 수 있습니다. 예를 들어, 명시된 Content-Length보다 긴 내용이 작성될 수 있습니다.
  • 본문 형식을 손상시킬 수 있습니다. 예를 들어, CSS 파일에 HTML 바닥글을 작성할 수 있습니다.

HasStarted는 헤더가 이미 전송됐는지 또는 본문이 이미 작성됐는지 여부를 나타내는 유용한 힌트를 제공해줍니다.

Run 대리자는 next 매개 변수를 받지 않습니다. 첫 번째 Run 대리자는 항상 터미널이며 파이프라인을 종료합니다. Run이 규칙입니다. 일부 미들웨어 구성 요소는 파이프라인의 끝에서 실행되는 Run[Middleware] 메서드를 노출할 수 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Do work that can write to the Response.
    await next.Invoke();
    // Do logging or other work that doesn't write to the Response.
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from 2nd delegate.");
});

app.Run();

영어 이외의 언어로 번역된 코드 주석을 보려면 이 GitHub 토론 이슈에서 알려주세요.

위 예제에서 Run 대리자는 응답에 "Hello from 2nd delegate."를 쓴 다음 파이프라인을 종료합니다. Run 대리자 뒤에 추가된 다른 Use 또는 Run 대리자는 호출되지 않습니다.

컨텍스트를 next로 전달해야 하는 app.Use 오버로드 선호

할당하지 않는 app.Use 확장 메서드:

  • 컨텍스트를 next로 전달해야 합니다.
  • 다른 오버로드를 사용할 때 필요한 두 개의 내부 요청당 할당을 저장합니다.

자세한 내용은 해당 GitHub 이슈를 참조하세요.

미들웨어 순서

다음 다이어그램은 ASP.NET Core MVC 및 Razor Pages 앱의 전체 요청 처리 파이프라인을 보여 줍니다. 일반적인 앱에서 기존 미들웨어의 순서가 지정되는 방식과 사용자 지정 미들웨어가 추가되는 위치를 볼 수 있습니다. 사용자는 원하는 대로 기존 미들웨어의 순서를 바꾸거나 시나리오의 필요에 따라 새 사용자 지정 미들웨어를 주입할 수 있습니다.

ASP.NET Core 미들웨어 파이프라인

앞에 나온 다이어그램의 엔드포인트 미들웨어는 해당 앱 형식(MVC 또는 Razor Pages)에 따라 필터 파이프라인을 실행합니다.

위 다이어그램의 라우팅 미들웨어는 정적 파일 다음에 표시됩니다. 이는 app.UseRouting을 명시적으로 호출하여 프로젝트 템플릿이 구현되는 순서입니다. app.UseRouting을 호출하지 않으면 라우팅 미들웨어는 기본적으로 파이프라인의 시작 부분에서 실행됩니다. 자세한 내용은 라우팅을 참조하세요.

ASP.NET Core 필터 파이프라인

미들웨어 구성 요소가 파일에 추가 Program.cs 되는 순서는 요청 시 미들웨어 구성 요소가 호출되는 순서와 응답의 역순을 정의합니다. 순서는 보안, 성능 및 기능에 중요합니다.

다음 강조 표시된 코드는 Program.cs 일반적인 권장 순서로 보안 관련 미들웨어 구성 요소를 추가합니다.

using IndividualAccountsExample.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
// app.UseCookiePolicy();

app.UseRouting();
// app.UseRequestLocalization();
// app.UseCors();

app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();

app.MapRazorPages();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

위의 코드에서

  • 개별 사용자 계정을 사용하여 새 웹앱을 만들 때 추가되지 않는 미들웨어는 주석 처리됩니다.
  • 모든 미들웨어가 정확한 순서로 표시되는 것은 아닙니다. 예:
    • UseCors, UseAuthentication, UseAuthorization은 표시된 순서로 표시되어야 합니다.
    • 현재 UseCorsUseResponseCaching보다 먼저 표시되어야 합니다. 이 요구 사항은 GitHub 이슈 dotnet/aspnetcore #23218에 설명되어 있습니다.
    • UseRequestLocalization은 요청 문화권(예: app.UseMvcWithDefaultRoute())을 확인할 수 있는 모든 미들웨어보다 먼저 표시되어야 합니다.

일부 시나리오의 경우 미들웨어는 다른 순서를 갖습니다. 예를 들어 캐싱 및 압축 순서는 시나리오마다 다르며 유효한 순서가 여러 개 있습니다. 예시:

app.UseResponseCaching();
app.UseResponseCompression();

위의 코드를 사용하면 압축된 응답을 캐싱하여 CPU 사용량을 줄일 수 있지만, Gzip 또는 Brotli와 같은 다른 압축 알고리즘을 사용하여 리소스의 여러 표현을 캐싱할 수도 있습니다.

다음 순서는 정적 파일을 결합하여 압축된 정적 파일 캐싱을 허용합니다.

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

다음 Program.cs 코드는 일반적인 앱 시나리오에 대한 미들웨어 구성 요소를 추가합니다.

  1. 예외/오류 처리
    • 개발 환경에서 앱이 실행되는 경우:
      • 개발자 예외 페이지 미들웨어(UseDeveloperExceptionPage)가 앱 런타임 오류를 보고합니다.
      • 데이터베이스 오류 페이지 미들웨어(UseDatabaseErrorPage)가 데이터베이스 런타임 오류를 보고합니다.
    • 앱이 프로덕션 환경에서 실행되는 경우:
      • 예외 처리기 미들웨어(UseExceptionHandler)가 다음 미들웨어에서 던져진 예외를 잡습니다.
      • HTTP HSTS(엄격한 전송 보안 프로토콜) 미들웨어(UseHsts)가 Strict-Transport-Security 헤더를 추가합니다.
  2. HTTPS 리디렉션 미들웨어(UseHttpsRedirection)가 HTTP 요청을 HTTPS로 리디렉션합니다.
  3. 정적 파일 미들웨어(UseStaticFiles)가 정적 파일을 반환하고 추가 요청 처리를 단락합니다.
  4. Cookie 정책 미들웨어(UseCookiePolicy)가 앱이 EU GDPR(일반 데이터 보호 규정)을 준수하도록 만듭니다.
  5. 요청을 라우팅하도록 미들웨어(UseRouting) 라우팅.
  6. 인증 미들웨어(UseAuthentication)가 보안 리소스에 대한 액세스가 허용되기 전에 사용자 인증을 시도합니다.
  7. 권한 부여 미들웨어(UseAuthorization)는 사용자에게 보안 리소스에 액세스할 수 있는 권한을 부여합니다.
  8. 세션 미들웨어(UseSession)가 세션 상태를 설정 및 유지합니다. 앱이 세션 상태를 사용하는 경우에는 Cookie 정책 미들웨어 이후 및 MVC 미들웨어 이전에 세션 미들웨어를 호출하세요.
  9. 엔드포인트 라우팅 미들웨어(MapRazorPages를 포함하는 UseEndpoints)를 사용하여 요청 파이프라인에 Razor Pages 엔드포인트를 추가합니다.
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseDatabaseErrorPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapRazorPages();

앞의 예제 코드에서 각 미들웨어 확장 메서드는 Microsoft.AspNetCore.Builder 네임스페이스를 통해 WebApplicationBuilder에 표시됩니다.

UseExceptionHandler는 파이프라인에 처음으로 추가된 미들웨어 구성 요소입니다. 따라서 예외 처리기 미들웨어는 후속 호출에서 발생하는 모든 예외를 catch 합니다.

정적 파일 미들웨어는 파이프라인 초기에 호출되므로 요청을 처리하고 나머지 구성 요소를 통과하지 않고 단락(short-circuit)할 수 있습니다. 정적 파일 미들웨어는 권한 부여 검사를 제공하지 않습니다. wwwroot에 있는 파일을 포함한 정적 파일 미들웨어에서 제공하는 모든 파일은 공개적으로 사용할 수 있습니다. 정적 파일을 보호하는 방법은 ASP.NET Core의 정적 파일을 참조하세요.

요청이 정적 파일 미들웨어에서 처리되지 않는 경우 인증을 수행하는 인증 미들웨어(UseAuthentication)로 전달됩니다. 인증은 인증되지 않은 요청을 단락(short-circuit)하지 않습니다. 인증 미들웨어가 요청을 인증하지만, MVC가 특정 Razor Page 또는 컨트롤러 및 작업을 선택한 후에만 권한 부여(및 거부)가 발생합니다.

다음 예제는 정적 파일에 대한 요청이 응답 압축 미들웨어 전에 정적 파일 미들웨어에서 처리되는 미들웨어 순서를 설명합니다. 정적 파일은 이 미들웨어 순서를 사용하여 압축되지 않습니다. Razor Pages 응답을 압축할 수 있습니다.

// Static files aren't compressed by Static File Middleware.
app.UseStaticFiles();

app.UseRouting();

app.UseResponseCompression();

app.MapRazorPages();

단일 페이지 애플리케이션에 대한 자세한 내용은 ReactAngular 프로젝트 템플릿 관련 가이드를 참조하세요.

UseCors 및 UseStaticFiles 순서

UseCorsUseStaticFiles 호출의 순서는 앱에 따라 달라집니다. 자세한 내용은 UseCors 및 UseStaticFiles 순서를 참조하세요.

전달된 헤더 미들웨어 순서

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

미들웨어 파이프라인 분기

Map 확장은 파이프라인 분기에 규칙으로 사용됩니다. Map은 지정된 요청 경로의 일치를 기반으로 요청 파이프라인을 분기합니다. 요청 경로가 지정된 경로로 시작하는 경우 분기가 실행됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1", HandleMapTest1);

app.Map("/map2", HandleMapTest2);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMapTest1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

static void HandleMapTest2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}

다음 표는 위의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/map1 Map Test 1
localhost:1234/map2 Map Test 2
localhost:1234/map3 Hello from non-Map delegate.

Map이 사용되는 경우 일치하는 경로 세그먼트는 HttpRequest.Path에서 제거되고 각 요청에 대해 HttpRequest.PathBase에 추가됩니다.

Map은 중첩을 지원합니다. 예를 들면 다음과 같습니다.

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map은 여러 세그먼트를 한 번에 일치시킬 수도 있습니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/map1/seg1", HandleMultiSeg);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 1");
    });
}

MapWhen은 지정된 조건자의 결과를 기반으로 요청 파이프라인을 분기합니다. Func<HttpContext, bool> 형식의 조건자는 파이프라인의 새 분기에 요청을 매핑하는 데 사용될 수 있습니다. 다음 예제에서 조건자는 쿼리 문자열 변수 branch의 존재를 검색하는 데 사용됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}

다음 표는 앞의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen도 지정된 조건자의 결과를 기준으로 요청 파이프라인을 분기합니다. MapWhen과 달리, 이 분기는 단락을 수행하거나 터미널 미들웨어를 포함하지 않는 경우 기본 파이프라인에 다시 연결됩니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
    appBuilder => HandleBranchAndRejoin(appBuilder));

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from non-Map delegate.");
});

app.Run();

void HandleBranchAndRejoin(IApplicationBuilder app)
{
    var logger = app.ApplicationServices.GetRequiredService<ILogger<Program>>(); 

    app.Use(async (context, next) =>
    {
        var branchVer = context.Request.Query["branch"];
        logger.LogInformation("Branch used = {branchVer}", branchVer);

        // Do work that doesn't write to the Response.
        await next();
        // Do other work that doesn't write to the Response.
    });
}

위의 예제에서 Hello from non-Map delegate. 응답은 모든 요청에 대해 기록됩니다. 요청에 쿼리 문자열 변수 branch가 포함되어 있으면, 기본 파이프라인이 다시 연결되기 전에 변수 값이 기록됩니다.

기본 제공 미들웨어

ASP.NET Core는 다음과 같은 미들웨어 구성 요소가 함께 제공됩니다. 순서 열은 요청 처리 파이프라인에서 미들웨어의 배치, 미들웨어가 요청 처리를 종료할 수 있는 조건에 대한 정보를 제공합니다. 미들웨어가 요청 처리 파이프라인을 단락(short-circuit)하고 후속 미들웨어가 더는 요청을 처리하지 못하도록 하는 경우 이를 터미널 미들웨어라고 합니다. 단락에 대한 자세한 내용은 WebApplication사용하여 미들웨어 파이프라인 만들기 섹션을 참조하세요.

미들웨어 설명 순서
인증 인증 지원을 제공합니다. HttpContext.User가 필요하기 전에. OAuth 콜백에 대한 터미널.
Authorization 권한 부여 지원을 제공합니다. 인증 미들웨어 바로 뒤에 있습니다.
Cookie 정책 개인 정보 저장과 관련한 사용자의 동의를 추적하고 cookie 필드(예: secureSameSite)에 대해 최소한의 표준을 적용합니다. 쿠키를 발행하는 미들웨어 전에. 예: 인증, 세션, MVC(TempData).
CORS 원본 간 리소스 공유를 구성합니다. CORS를 사용하는 구성 요소 이전. 현재 UseCors이 버그로 인해 UseResponseCaching보다 먼저 사용됩니다.
DeveloperExceptionPage 개발 환경에서만 사용하기 위한 오류 정보가 포함된 페이지를 생성합니다. 오류를 생성하는 구성 요소 이전. 프로젝트 템플릿은 환경이 개발일 때 이 미들웨어를 파이프라인의 첫 번째 미들웨어로 자동으로 등록합니다.
진단 개발자 예외 페이지, 예외 처리, 상태 코드 페이지 및 새 앱에 대한 기본 웹 페이지를 제공하는 몇 가지 개별 미들웨어. 오류를 생성하는 구성 요소 이전. 예외가 발생하거나 새 앱의 기본 웹 페이지를 처리하는 터미널입니다.
전달된 헤더 프록시된 헤더를 현재 요청에 전달합니다. 업데이트된 필드를 사용하는 구성 요소 전에. 예: 체계, 호스트, 클라이언트 IP, 메서드.
상태 확인 ASP.NET Core 앱 및 그 종속성(데이터베이스 가용성 등)의 상태를 검사합니다. 요청이 상태 검사 엔드포인트와 일치하는 경우 마지막입니다.
헤더 전파 들어오는 요청에서 나가는 HTTP 클라이언트 요청으로 HTTP 헤더를 전파합니다.
HTTP 로깅 HTTP 요청 및 응답을 로그합니다. 미들웨어 파이프라인의 시작 부분에서.
HTTP 메서드 재정의 들어오는 POST 요청이 메서드를 재정의하도록 허용합니다. 업데이트된 메서드를 사용하는 구성 요소 앞입니다.
HTTPS 리디렉션 모든 HTTP 요청을 HTTPS로 리디렉션합니다. URL을 사용하는 구성 요소 이전.
HSTS(HTTP 엄격한 전송 보안) 특별한 응답 헤더를 추가하는 보안 향상 미들웨어입니다. 응답이 전송되기 이전, 요청을 수정하는 구성 요소 이후에. 예: 전달된 헤더, URL 재작성.
MVC MVC/Razor Pages를 사용하여 요청을 처리합니다. 요청이 경로와 일치하는 경우 터미널입니다.
OWIN OWIN 기반 앱, 서버 및 미들웨어와 상호 운용됩니다. OWIN 미들웨어가 요청을 완벽하게 처리하는 경우 터미널입니다.
요청 압축 해제 요청 압축 해제를 지원합니다. 요청 본문을 읽는 구성 요소 이전
응답 캐싱 응답 캐시에 대한 지원을 제공합니다. 캐싱이 필요한 구성 요소 이전. UseCORSUseResponseCaching 앞에 와야 합니다.
응답 압축 응답 압축에 대한 지원을 제공합니다. 압축이 필요한 구성 요소 이전.
요청 지역화 지역화 지원을 제공합니다. 지역화 구분 구성 요소 이전. RouteDataRequestCultureProvider를 사용할 경우 라우팅 미들웨어 뒤에 표시되어야 합니다.
엔드포인트 라우팅 요청 경로를 정의하고 제한합니다. 경로 일치에 대한 터미널.
스파 SPA(단일 페이지 애플리케이션)의 기반 페이지를 반환하여 이 시점부터 미들웨어 체인의 모든 요청을 처리합니다. 정적 파일, MVC 작업 등을 처리하는 다른 미들웨어가 우선할 수 있도록 이 미들웨어는 체인에서 늦게 배치되어야 합니다.
세션 사용자 세션 관리에 대한 지원을 제공합니다. 세션이 필요한 구성 요소 이전.
정적 파일 정적 파일 및 디렉터리 검색 처리에 대한 지원을 제공합니다. 요청이 파일과 일치하는 경우 터미널입니다.
URL 재작성 URL 재작성 및 요청 리디렉션에 대한 지원을 제공합니다. URL을 사용하는 구성 요소 이전.
W3CLogging W3C 확장 로그 파일 형식으로 서버 액세스 로그를 생성합니다. 미들웨어 파이프라인의 시작 부분에서.
WebSocket WebSocket 프로토콜을 활성화합니다. WebSocket 요청을 수락하는 데 필요한 구성 요소 이전.

추가 리소스

작성자: Rick AndersonSteve Smith

미들웨어는 요청 및 응답을 처리하는 앱 파이프라인으로 어셈블리되는 소프트웨어입니다. 각 구성 요소:

  • 요청을 파이프라인의 다음 구성 요소로 전달할지 여부를 선택합니다.
  • 파이프라인의 다음 구성 요소 전과 후에 작업을 수행할 수 있습니다.

요청 대리자는 요청 파이프라인을 빌드하는 데 사용됩니다. 요청 대리자는 각 HTTP 요청을 처리합니다.

요청 대리자는 Run, MapUse 확장 메서드를 사용하여 구성됩니다. 개별 요청 대리자는 무명 메서드(인라인 미들웨어라고 함)로 인라인에서 지정되거나 다시 사용할 수 있는 클래스에서 정의될 수 있습니다. 이러한 다시 사용할 수 있는 클래스 및 인라인 무명 메서드를 미들웨어라고 하며, 미들웨어 구성 요소라고 부르기도 합니다. 요청 파이프라인의 각 미들웨어 구성 요소는 파이프라인의 그 다음 구성 요소를 호출하거나 파이프라인을 단락(short-circuiting)하는 역할을 담당합니다. 미들웨어가 단락(short-circuit)되는 경우 미들웨어에서 더는 요청을 처리하지 못하도록 하기 때문에 이를 터미널 미들웨어라고 합니다.

HTTP 핸들러 및 모듈을 ASP.NET Core 미들웨어로 마이그레이션에서는 ASP.NET Core와 ASP.NET 4.x 간의 요청 파이프라인 차이점을 설명하고 더 많은 미들웨어 샘플을 제공합니다.

IApplicationBuilder로 미들웨어 파이프라인 만들기

ASP.NET Core 요청 파이프라인은 하나씩 차례로 호출되는 요청 대리자 시퀀스로 구성됩니다. 다음 다이어그램은 그 개념을 보여줍니다. 실행 스레드는 검은색 화살표를 따릅니다.

요청이 도착하고, 세 개의 미들웨어를 통해 처리하고, 앱에서 응답이 나가는 것을 보여주는 요청 처리 패턴입니다. 각 미들웨어는 해당 논리를 실행하고 next() 문에서 다음 미들웨어로 요청을 전달합니다. 세 번째 미들웨어가 요청을 처리한 후, 클라이언트에 대한 응답으로 앱을 떠나기 전에 해당 next() 문 이후 추가 처리에 대해 반대 순서로 이전의 미들웨어 두 개를 통해 요청을 다시 전달합니다.

각 대리자는 다음 대리자 전과 후에 작업을 수행할 수 있습니다. 예외 처리 대리자는 파이프라인의 이후 단계에서 발생하는 예외를 잡을 수 있도록 파이프라인의 초기에 호출되어야 합니다.

가장 간단한 가능한 ASP.NET Core 앱은 모든 요청을 처리하는 단일 요청 대리자를 설정합니다. 이 경우 실제 요청 파이프라인은 포함되지 않습니다. 대신, 단일 익명 함수가 모든 HTTP 요청에 대한 응답에 호출됩니다.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello, World!");
        });
    }
}

Use를 사용하여 여러 요청 대리자를 연결합니다. next 매개 변수는 파이프라인의 다음 대리자를 나타냅니다. next 매개 변수를 호출하지 않고 파이프라인을 단락(short-circuit)할 수 있습니다. 다음 예제의 설명처럼, 일반적으로 다음 대리자 전과 후 모두에서 작업을 수행할 수 있습니다.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

대리자가 다음 대리자에 요청을 전달하지 않을 때 이를 요청 파이프라인을 단락(short-circuiting)한다고 합니다. 단락(short-circuiting)은 불필요한 작업을 방지하기 때문에 종종 바람직합니다. 예를 들어 정적 파일 미들웨어는 정적 파일에 대한 요청을 처리하고 파이프라인의 단락을 통해 rest 터미널 미들웨어 역할을 할 수 있습니다. 추가 처리를 종료하는 미들웨어 전에 파이프라인에 추가된 미들웨어는 next.Invoke 문 이후의 코드를 계속 처리합니다. 그러나 이미 전송된 응답에 쓰려고 시도하는 것에 대한 다음 경고를 참조하세요.

Warning

클라이언트에 응답을 전송한 후에 next.Invoke를 호출하지 마십시오. 응답이 시작된 후 HttpResponse로 변경하면 예외를 던집니다. 예를 들어 헤더 및 상태 코드를 설정하면 예외를 throw합니다. next를 호출한 후 응답 본문에 작성할 경우:

  • 프로토콜 위반이 발생할 수 있습니다. 예를 들어, 명시된 Content-Length보다 긴 내용이 작성될 수 있습니다.
  • 본문 형식을 손상시킬 수 있습니다. 예를 들어, CSS 파일에 HTML 바닥글을 작성할 수 있습니다.

HasStarted는 헤더가 이미 전송됐는지 또는 본문이 이미 작성됐는지 여부를 나타내는 유용한 힌트를 제공해줍니다.

Run 대리자는 next 매개 변수를 받지 않습니다. 첫 번째 Run 대리자는 항상 터미널이며 파이프라인을 종료합니다. Run이 규칙입니다. 일부 미들웨어 구성 요소는 파이프라인의 끝에서 실행되는 Run[Middleware] 메서드를 노출할 수 있습니다.

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

영어 이외의 언어로 번역된 코드 주석을 보려면 이 GitHub 토론 이슈에서 알려주세요.

위 예제에서 Run 대리자는 응답에 "Hello from 2nd delegate."를 쓴 다음 파이프라인을 종료합니다. Run 대리자 뒤에 추가된 다른 Use 또는 Run 대리자는 호출되지 않습니다.

미들웨어 순서

다음 다이어그램은 ASP.NET Core MVC 및 Razor Pages 앱의 전체 요청 처리 파이프라인을 보여 줍니다. 일반적인 앱에서 기존 미들웨어의 순서가 지정되는 방식과 사용자 지정 미들웨어가 추가되는 위치를 볼 수 있습니다. 사용자는 원하는 대로 기존 미들웨어의 순서를 바꾸거나 시나리오의 필요에 따라 새 사용자 지정 미들웨어를 주입할 수 있습니다.

ASP.NET Core 미들웨어 파이프라인

앞에 나온 다이어그램의 엔드포인트 미들웨어는 해당 앱 형식(MVC 또는 Razor Pages)에 따라 필터 파이프라인을 실행합니다.

ASP.NET Core 필터 파이프라인

미들웨어 구성 요소가 Startup.Configure 메서드에 추가되는 순서는 요청에서 미들웨어 구성 요소가 호출되는 순서와 응답에 대한 역순서를 정의합니다. 순서는 보안, 성능 및 기능에 중요합니다.

다음 Startup.Configure 메서드는 보안 관련 미들웨어 구성 요소를 일반적인 권장 순서에 따라 추가합니다.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    // app.UseCookiePolicy();

    app.UseRouting();
    // app.UseRequestLocalization();
    // app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();
    // app.UseSession();
    // app.UseResponseCompression();
    // app.UseResponseCaching();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

위의 코드에서

  • 개별 사용자 계정을 사용하여 새 웹앱을 만들 때 추가되지 않는 미들웨어는 주석 처리됩니다.
  • 모든 미들웨어가 정확한 순서로 표시되는 것은 아닙니다. 예:
    • UseCors, UseAuthentication, UseAuthorization은 표시된 순서로 표시되어야 합니다.
    • 현재 UseCors이 버그로 인해 UseResponseCaching보다 먼저 표시되어야 합니다.
    • UseRequestLocalization은 요청 문화권(예: app.UseMvcWithDefaultRoute())을 확인할 수 있는 모든 미들웨어보다 먼저 표시되어야 합니다.

일부 시나리오의 경우 미들웨어는 다른 순서를 갖습니다. 예를 들어 캐싱 및 압축 순서는 시나리오마다 다르며 유효한 순서가 여러 개 있습니다. 예시:

app.UseResponseCaching();
app.UseResponseCompression();

위의 코드를 사용하면 압축된 응답을 캐싱하여 CPU를 저장할 수 있지만 Gzip 또는 Brotli와 같은 다른 압축 알고리즘을 사용하여 리소스의 여러 표현을 캐싱할 수도 있습니다.

다음 순서는 정적 파일을 결합하여 압축된 정적 파일 캐싱을 허용합니다.

app.UseResponseCaching();
app.UseResponseCompression();
app.UseStaticFiles();

다음 Startup.Configure 메서드는 공통 앱 시나리오를 위한 미들웨어 구성 요소를 추가합니다.

  1. 예외/오류 처리
    • 개발 환경에서 앱이 실행되는 경우:
      • 개발자 예외 페이지 미들웨어(UseDeveloperExceptionPage)가 앱 런타임 오류를 보고합니다.
      • 데이터베이스 오류 페이지 미들웨어가 데이터베이스 런타임 오류를 보고합니다.
    • 앱이 프로덕션 환경에서 실행되는 경우:
      • 예외 처리기 미들웨어(UseExceptionHandler)가 다음 미들웨어에서 던져진 예외를 잡습니다.
      • HTTP HSTS(엄격한 전송 보안 프로토콜) 미들웨어(UseHsts)가 Strict-Transport-Security 헤더를 추가합니다.
  2. HTTPS 리디렉션 미들웨어(UseHttpsRedirection)가 HTTP 요청을 HTTPS로 리디렉션합니다.
  3. 정적 파일 미들웨어(UseStaticFiles)가 정적 파일을 반환하고 추가 요청 처리를 단락합니다.
  4. Cookie 정책 미들웨어(UseCookiePolicy)가 앱이 EU GDPR(일반 데이터 보호 규정)을 준수하도록 만듭니다.
  5. 요청을 라우팅하도록 미들웨어(UseRouting) 라우팅.
  6. 인증 미들웨어(UseAuthentication)가 보안 리소스에 대한 액세스가 허용되기 전에 사용자 인증을 시도합니다.
  7. 권한 부여 미들웨어(UseAuthorization)는 사용자에게 보안 리소스에 액세스할 수 있는 권한을 부여합니다.
  8. 세션 미들웨어(UseSession)가 세션 상태를 설정 및 유지합니다. 앱이 세션 상태를 사용하는 경우에는 Cookie 정책 미들웨어 이후 및 MVC 미들웨어 이전에 세션 미들웨어를 호출하세요.
  9. 엔드포인트 라우팅 미들웨어(MapRazorPages를 포함하는 UseEndpoints)를 사용하여 요청 파이프라인에 Razor Pages 엔드포인트를 추가합니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseSession();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

앞의 예제 코드에서 각 미들웨어 확장 메서드는 Microsoft.AspNetCore.Builder 네임스페이스를 통해 IApplicationBuilder에 표시됩니다.

UseExceptionHandler는 파이프라인에 처음으로 추가된 미들웨어 구성 요소입니다. 따라서 예외 처리기 미들웨어는 후속 호출에서 발생하는 모든 예외를 catch 합니다.

정적 파일 미들웨어는 파이프라인 초기에 호출되므로 요청을 처리하고 나머지 구성 요소를 통과하지 않고 단락(short-circuit)할 수 있습니다. 정적 파일 미들웨어는 권한 부여 검사를 제공하지 않습니다. wwwroot에 있는 파일을 포함한 정적 파일 미들웨어에서 제공하는 모든 파일은 공개적으로 사용할 수 있습니다. 정적 파일을 보호하는 방법은 ASP.NET Core의 정적 파일을 참조하세요.

요청이 정적 파일 미들웨어에서 처리되지 않는 경우 인증을 수행하는 인증 미들웨어(UseAuthentication)로 전달됩니다. 인증은 인증되지 않은 요청을 단락(short-circuit)하지 않습니다. 인증 미들웨어가 요청을 인증하지만, MVC가 특정 Razor Page 또는 컨트롤러 및 작업을 선택한 후에만 권한 부여(및 거부)가 발생합니다.

다음 예제는 정적 파일에 대한 요청이 응답 압축 미들웨어 전에 정적 파일 미들웨어에서 처리되는 미들웨어 순서를 설명합니다. 정적 파일은 이 미들웨어 순서를 사용하여 압축되지 않습니다. Razor Pages 응답을 압축할 수 있습니다.

public void Configure(IApplicationBuilder app)
{
    // Static files aren't compressed by Static File Middleware.
    app.UseStaticFiles();

    app.UseRouting();

    app.UseResponseCompression();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

SPA(단일 페이지 애플리케이션)의 경우 SPA 미들웨어 UseSpaStaticFiles는 일반적으로 미들웨어 파이프라인에서 마지막으로 나옵니다. SPA 미들웨어가 마지막으로 나오는 이유는 다음과 같습니다.

  • 다른 모든 미들웨어가 일치하는 요청에 먼저 응답하도록 합니다.
  • 클라이언트 쪽 라우팅이 있는 SPA가 서버 앱에서 인식할 수 없는 모든 경로에 대해 실행되도록 합니다.

SPA에 대한 자세한 내용은 ReactAngular 프로젝트 템플릿 관련 가이드를 참조하세요.

전달된 헤더 미들웨어 순서

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

미들웨어 파이프라인 분기

Map 확장은 파이프라인 분기에 규칙으로 사용됩니다. Map은 지정된 요청 경로의 일치를 기반으로 요청 파이프라인을 분기합니다. 요청 경로가 지정된 경로로 시작하는 경우 분기가 실행됩니다.

public class Startup
{
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }

    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);

        app.Map("/map2", HandleMapTest2);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

다음 표는 앞의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/map1 Map Test 1
localhost:1234/map2 Map Test 2
localhost:1234/map3 Hello from non-Map delegate.

Map이 사용되는 경우 일치하는 경로 세그먼트는 HttpRequest.Path에서 제거되고 각 요청에 대해 HttpRequest.PathBase에 추가됩니다.

Map은 중첩을 지원합니다. 예를 들면 다음과 같습니다.

app.Map("/level1", level1App => {
    level1App.Map("/level2a", level2AApp => {
        // "/level1/level2a" processing
    });
    level1App.Map("/level2b", level2BApp => {
        // "/level1/level2b" processing
    });
});

Map은 여러 세그먼트를 한 번에 일치시킬 수도 있습니다.

public class Startup
{
    private static void HandleMultiSeg(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map multiple segments.");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1/seg1", HandleMultiSeg);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

MapWhen은 지정된 조건자의 결과를 기반으로 요청 파이프라인을 분기합니다. Func<HttpContext, bool> 형식의 조건자는 파이프라인의 새 분기에 요청을 매핑하는 데 사용될 수 있습니다. 다음 예제에서 조건자는 쿼리 문자열 변수 branch의 존재를 검색하는 데 사용됩니다.

public class Startup
{
    private static void HandleBranch(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            var branchVer = context.Request.Query["branch"];
            await context.Response.WriteAsync($"Branch used = {branchVer}");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.MapWhen(context => context.Request.Query.ContainsKey("branch"),
                               HandleBranch);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate.");
        });
    }
}

다음 표는 앞의 코드를 사용하여 http://localhost:1234의 요청 및 응답을 보여 줍니다.

Request 응답
localhost:1234 Hello from non-Map delegate.
localhost:1234/?branch=main Branch used = main

UseWhen도 지정된 조건자의 결과를 기준으로 요청 파이프라인을 분기합니다. MapWhen과 달리, 이 분기는 단락을 수행하거나 터미널 미들웨어를 포함하지 않는 경우 기본 파이프라인에 다시 연결됩니다.

public class Startup
{
    private void HandleBranchAndRejoin(IApplicationBuilder app, ILogger<Startup> logger)
    {
        app.Use(async (context, next) =>
        {
            var branchVer = context.Request.Query["branch"];
            logger.LogInformation("Branch used = {branchVer}", branchVer);

            // Do work that doesn't write to the Response.
            await next();
            // Do other work that doesn't write to the Response.
        });
    }

    public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
    {
        app.UseWhen(context => context.Request.Query.ContainsKey("branch"),
                               appBuilder => HandleBranchAndRejoin(appBuilder, logger));

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from main pipeline.");
        });
    }
}

위의 예제에서 "Hello from main pipeline." 응답은 모든 요청에 대해 기록됩니다. 요청에 쿼리 문자열 변수 branch가 포함되어 있으면, 기본 파이프라인이 다시 연결되기 전에 변수 값이 기록됩니다.

기본 제공 미들웨어

ASP.NET Core는 다음과 같은 미들웨어 구성 요소가 함께 제공됩니다. 순서 열은 요청 처리 파이프라인에서 미들웨어의 배치, 미들웨어가 요청 처리를 종료할 수 있는 조건에 대한 정보를 제공합니다. 미들웨어가 요청 처리 파이프라인을 단락(short-circuit)하고 후속 미들웨어가 더는 요청을 처리하지 못하도록 하는 경우 이를 터미널 미들웨어라고 합니다. 단락(short-circuiting)에 대한 자세한 내용은 IApplicationBuilder로 미들웨어 파이프라인 만들기 섹션을 참조하세요.

미들웨어 설명 순서
인증 인증 지원을 제공합니다. HttpContext.User가 필요하기 전에. OAuth 콜백에 대한 터미널.
Authorization 권한 부여 지원을 제공합니다. 인증 미들웨어 바로 뒤에 있습니다.
Cookie 정책 개인 정보 저장과 관련한 사용자의 동의를 추적하고 cookie 필드(예: secureSameSite)에 대해 최소한의 표준을 적용합니다. 쿠키를 발행하는 미들웨어 전에. 예: 인증, 세션, MVC(TempData).
CORS 원본 간 리소스 공유를 구성합니다. CORS를 사용하는 구성 요소 이전. 현재 UseCors이 버그로 인해 UseResponseCaching보다 먼저 사용됩니다.
진단 개발자 예외 페이지, 예외 처리, 상태 코드 페이지 및 새 앱에 대한 기본 웹 페이지를 제공하는 몇 가지 개별 미들웨어. 오류를 생성하는 구성 요소 이전. 예외가 발생하거나 새 앱의 기본 웹 페이지를 처리하는 터미널입니다.
전달된 헤더 프록시된 헤더를 현재 요청에 전달합니다. 업데이트된 필드를 사용하는 구성 요소 전에. 예: 체계, 호스트, 클라이언트 IP, 메서드.
상태 확인 ASP.NET Core 앱 및 그 종속성(데이터베이스 가용성 등)의 상태를 검사합니다. 요청이 상태 검사 엔드포인트와 일치하는 경우 마지막입니다.
헤더 전파 들어오는 요청에서 나가는 HTTP 클라이언트 요청으로 HTTP 헤더를 전파합니다.
HTTP 메서드 재정의 들어오는 POST 요청이 메서드를 재정의하도록 허용합니다. 업데이트된 메서드를 사용하는 구성 요소 앞입니다.
HTTPS 리디렉션 모든 HTTP 요청을 HTTPS로 리디렉션합니다. URL을 사용하는 구성 요소 이전.
HSTS(HTTP 엄격한 전송 보안) 특별한 응답 헤더를 추가하는 보안 향상 미들웨어입니다. 응답이 전송되기 이전, 요청을 수정하는 구성 요소 이후에. 예: 전달된 헤더, URL 재작성.
MVC MVC/Razor Pages를 사용하여 요청을 처리합니다. 요청이 경로와 일치하는 경우 터미널입니다.
OWIN OWIN 기반 앱, 서버 및 미들웨어와 상호 운용됩니다. OWIN 미들웨어가 요청을 완벽하게 처리하는 경우 터미널입니다.
응답 캐싱 응답 캐시에 대한 지원을 제공합니다. 캐싱이 필요한 구성 요소 이전. UseCORSUseResponseCaching 앞에 와야 합니다.
응답 압축 응답 압축에 대한 지원을 제공합니다. 압축이 필요한 구성 요소 이전.
요청 지역화 지역화 지원을 제공합니다. 지역화 구분 구성 요소 이전. RouteDataRequestCultureProvider를 사용할 경우 라우팅 미들웨어 뒤에 표시되어야 합니다.
엔드포인트 라우팅 요청 경로를 정의하고 제한합니다. 경로 일치에 대한 터미널.
스파 SPA(단일 페이지 애플리케이션)의 기반 페이지를 반환하여 이 시점부터 미들웨어 체인의 모든 요청을 처리합니다. 정적 파일, MVC 작업 등을 처리하는 다른 미들웨어가 우선할 수 있도록 이 미들웨어는 체인에서 늦게 배치되어야 합니다.
세션 사용자 세션 관리에 대한 지원을 제공합니다. 세션이 필요한 구성 요소 이전.
정적 파일 정적 파일 및 디렉터리 검색 처리에 대한 지원을 제공합니다. 요청이 파일과 일치하는 경우 터미널입니다.
URL 재작성 URL 재작성 및 요청 리디렉션에 대한 지원을 제공합니다. URL을 사용하는 구성 요소 이전.
WebSocket WebSocket 프로토콜을 활성화합니다. WebSocket 요청을 수락하는 데 필요한 구성 요소 이전.

추가 리소스