ASP.NET Core 中介軟體ASP.NET Core Middleware

Rick AndersonSteve Smith 撰寫By Rick Anderson and Steve Smith

中介軟體為組成應用程式管線的軟體,用以處理要求與回應。Middleware is software that's assembled into an app pipeline to handle requests and responses. 每個元件:Each component:

  • 可選擇是否要將要求傳送到管線中的下一個元件。Chooses whether to pass the request to the next component in the pipeline.
  • 可以下一個元件的前後執行工作。Can perform work before and after the next component in the pipeline.

要求委派用於建置要求管線,Request delegates are used to build the request pipeline. 其會處理每個 HTTP 要求。The request delegates handle each HTTP request.

要求委派的設定方式為使用 RunMapUse 擴充方法。Request delegates are configured using Run, Map, and Use extension methods. 您可將個別要求委派指定為內嵌匿名方法 (在內嵌中介軟體中呼叫),或於可重複使用的類別中加以定義。An individual request delegate can be specified in-line as an anonymous method (called in-line middleware), or it can be defined in a reusable class. 這些可重複使用的類別及內嵌匿名方法皆為「中介軟體」 ,也稱為「中介軟體元件」 。These reusable classes and in-line anonymous methods are middleware, also called middleware components. 要求管線中的每個中介軟體元件負責叫用管線中下一個元件,或對管線執行最少運算。Each middleware component in the request pipeline is responsible for invoking the next component in the pipeline or short-circuiting the pipeline. 當中介軟體短路時,稱為「終端中介軟體」 ,因為它會防止接下來的中介軟體處理要求。When a middleware short-circuits, it's called a terminal middleware because it prevents further middleware from processing the request.

將 HTTP 處理常式和模組移轉至 ASP.NET Core 中介軟體 說明 ASP.NET Core 和 ASP.NET 4.x 之間的要求管線差異,並提供更多中介軟體範例。將 HTTP 處理常式和模組移轉至 ASP.NET Core 中介軟體 explains the difference between request pipelines in ASP.NET Core and ASP.NET 4.x and provides additional middleware samples.

使用 IApplicationBuilder 建立中介軟體管線Create a middleware pipeline with IApplicationBuilder

ASP.NET Core 要求管線由要求委派序列組成,並會一個接著一個呼叫。The ASP.NET Core request pipeline consists of a sequence of request delegates, called one after the other. 下圖說明此概念。The following diagram demonstrates the concept. 執行緒遵循黑色箭號執行。The thread of execution follows the black arrows.

要求處理模式說明要求抵達,經過三個中介軟體所處理,然後應用程式送出回應。

每一個委派皆能在下個委派的前後執行作業。Each delegate can perform operations before and after the next delegate. 處理例外狀況的委派必須提前在管線中呼叫,以便其可與管線後續階段中所發生的例外狀況達成一致。Exception-handling delegates should be called early in the pipeline, so they can catch exceptions that occur in later stages of the pipeline.

最簡潔的 ASP.NET Core 應用程式會設定單一要求委派來處理所有要求。The simplest possible ASP.NET Core app sets up a single request delegate that handles all requests. 此情況不包含實際要求管線。This case doesn't include an actual request pipeline. 反之,系統會呼叫單一匿名函式來回應每個 HTTP 要求。Instead, a single anonymous function is called in response to every HTTP request.

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

第一個 Run 委派會終止管線。The first Run delegate terminates the pipeline.

將多個要求委派鏈結在一起的方法是使用 UseChain multiple request delegates together with Use. next 參數代表管線中的下個委派。The next parameter represents the next delegate in the pipeline. 您可以「不」 呼叫「下一個」 參數來對管線執行最少運算。You can short-circuit the pipeline by not calling the next parameter. 您通常可以在下個委派的前後執行動作,如下列範例所示:You can typically perform actions both before and after the next delegate, as the following example demonstrates:

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

當委派不將要求傳遞到下一個委派時,這就是所謂讓要求管線短路When a delegate doesn't pass a request to the next delegate, it's called short-circuiting the request pipeline. 因為最少運算可避免不必要的工作,所以經常使用。Short-circuiting is often desirable because it avoids unnecessary work. 例如,靜態檔案中介軟體可以做為終端中介軟體使用,方式是處理靜態檔案的要求,並對剩餘的管線執行短路。For example, Static File Middleware can act as a terminal middleware by processing a request for a static file and short-circuiting the rest of the pipeline. 在中介軟體之前新增到管線且終結進一步處理的中介軟體在其 next.Invoke 陳述式之後仍然處理程式碼。Middleware added to the pipeline before the middleware that terminates further processing still processes code after their next.Invoke statements. 不過,查看下列有關嘗試寫入已傳送之回應的警告。However, see the following warning about attempting to write to a response that has already been sent.

警告

請不要在回應已傳送給用戶端之後呼叫 next.InvokeDon't call next.Invoke after the response has been sent to the client. 回應啟動後,變更為 HttpResponse 會擲回例外狀況。Changes to HttpResponse after the response has started throw an exception. 例如,變更設定標頭、狀態碼等都會擲回例外狀況。For example, changes such as setting headers and a status code throw an exception. 若在呼叫 next 後寫入回應本文:Writing to the response body after calling next:

  • 可能導致違反通訊協定。May cause a protocol violation. 例如,寫入超過指定 Content-Length 的內容。For example, writing more than the stated Content-Length.
  • 可能損毀本文格式。May corrupt the body format. 例如,將 HTML 頁尾寫入 CSS 檔。For example, writing an HTML footer to a CSS file.

HasStarted 是實用的提示,可表示是否已傳送標頭 (或) 是否已寫入本文。HasStarted is a useful hint to indicate if headers have been sent or the body has been written to.

順序Order

Startup.Configure 方法內中介軟體元件的新增順序可定義在要求時叫用中介軟體元件的順序及回應的反向順序。The order that middleware components are added in the Startup.Configure method defines the order in which the middleware components are invoked on requests and the reverse order for the response. 對安全性、效能與功能性而言,此順序相當重要。The order is critical for security, performance, and functionality.

下列 Startup.Configure 方法會新增適用於一般應用程式案例的中介軟體元件:The following Startup.Configure method adds middleware components for common app scenarios:

  1. 例外狀況/錯誤處理Exception/error handling
    • 當應用程式在開發環境中執行時:When the app runs in the Development environment:
    • 當應用程式在生產環境中執行時:When the app runs in the Production environment:
      • 例外狀況處理常式中介軟體 (UseExceptionHandler) 會攔截在下列中介軟體中擲回的例外狀況。Exception Handler Middleware (UseExceptionHandler) catches exceptions thrown in the following middlewares.
      • HTTP 靜態傳輸安全性通訊協定 (HSTS) 中介軟體 (UseHsts) 會新增 Strict-Transport-Security 標頭。HTTP Strict Transport Security Protocol (HSTS) Middleware (UseHsts) adds the Strict-Transport-Security header.
  2. HTTPS 重新導向中介軟體 (UseHttpsRedirection) 會將 HTTP 要求重新導向到 HTTPS。HTTPS Redirection Middleware (UseHttpsRedirection) redirects HTTP requests to HTTPS.
  3. 靜態檔案中介軟體 (UseStaticFiles) 會傳回靜態檔案並縮短進一步的要求處理時間。Static File Middleware (UseStaticFiles) returns static files and short-circuits further request processing.
  4. Cookie 原則中介軟體 (UseCookiePolicy) 會使應用程式符合歐盟一般資料保護歸調 (GDPR) 法規。Cookie Policy Middleware (UseCookiePolicy) conforms the app to the EU General Data Protection Regulation (GDPR) regulations.
  5. 驗證中介軟體 (UseAuthentication) 會嘗試在允許使用者存取安全資源之前先驗證使用者。Authentication Middleware (UseAuthentication) attempts to authenticate the user before they're allowed access to secure resources.
  6. 工作階段中介軟體 (UseSession) 會建立並維護工作階段狀態。Session Middleware (UseSession) establishes and maintains session state. 若應用程式使用工作階段狀態,請在 Cookie 原則中介軟體之後、MVC 中介軟體之前呼叫工作階段中介軟體。If the app uses session state, call Session Middleware after Cookie Policy Middleware and before MVC Middleware.
  7. MVC (UseMvc) 以將 MVC 新增到要求管線。MVC (UseMvc) to add MVC to the request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseAuthentication();
    app.UseSession();
    app.UseMvc();
}

在上面的範例程式碼中,每個中介軟體擴充方法都會透過 Microsoft.AspNetCore.Builder 命名空間在 IApplicationBuilder 上公開。In the preceding example code, each middleware extension method is exposed on IApplicationBuilder through the Microsoft.AspNetCore.Builder namespace.

UseExceptionHandler 是第一個新增到管道的中介軟體元件。UseExceptionHandler is the first middleware component added to the pipeline. 因此,例外處理常式中介軟體會攔截後續呼叫中發生的所有例外狀況。Therefore, the Exception Handler Middleware catches any exceptions that occur in later calls.

靜態檔案中介軟體會提前在管線中呼叫,以便其無須逐一處理剩餘的元件,就能處理要求及執行最少運算。Static File Middleware is called early in the pipeline so that it can handle requests and short-circuit without going through the remaining components. 靜態檔案中介軟體不會執行授權檢查。The Static File Middleware provides no authorization checks. 其提供的所有檔案,包括在 wwwroot 下的檔案,皆可公開使用。Any files served by it, including those under wwwroot, are publicly available. 如需保護靜態檔案的方法,請參閱 ASP.NET Core 中的靜態檔案For an approach to secure static files, see ASP.NET Core 中的靜態檔案.

若靜態檔案中介軟體未處理要求,該要求會繼續傳遞給執行驗證的驗證中介軟體 (UseAuthentication)。If the request isn't handled by the Static File Middleware, it's passed on to the Authentication Middleware (UseAuthentication), which performs authentication. 驗證不會對未經驗證的要求執行最少運算。Authentication doesn't short-circuit unauthenticated requests. 雖然驗證中介軟體會驗證要求,但只有在 MVC 選取特定 Razor 頁面或 MVC 控制器及動作後,才會進行驗證 (與拒絕)。Although Authentication Middleware authenticates requests, authorization (and rejection) occurs only after MVC selects a specific Razor Page or MVC controller and action.

下列範例示範靜態檔案中介軟體在回應壓縮中介軟體之前處理靜態檔案要求之前的靜態檔案順序。The following example demonstrates a middleware order where requests for static files are handled by Static File Middleware before Response Compression Middleware. 靜態檔案並不會以此中介軟體順序壓縮。Static files aren't compressed with this middleware order. 來自 UseMvcWithDefaultRoute 的 MVC 回應可壓縮。The MVC responses from UseMvcWithDefaultRoute can be compressed.

public void Configure(IApplicationBuilder app)
{
    // Static files not compressed by Static File Middleware.
    app.UseStaticFiles();
    app.UseResponseCompression();
    app.UseMvcWithDefaultRoute();
}

Use、Run 與 MapUse, Run, and Map

設定 HTTP 管線的方法是使用 UseRunMapConfigure the HTTP pipeline using Use, Run, and Map. Use 方法可對管線執行最少運算 (亦即,如果其不呼叫 next 要求委派的情況下)。The Use method can short-circuit the pipeline (that is, if it doesn't call a next request delegate). Run 是一種慣例,且有些中介軟體元件可能將執行於管線尾端的 Run[Middleware] 方法公開。Run is a convention, and some middleware components may expose Run[Middleware] methods that run at the end of the pipeline.

Map 擴充方法則是用來分支管線的慣例。Map extensions are used as a convention for branching the pipeline. Map 會依據指定要求路徑的相符項目將要求管線分支。Map branches the request pipeline based on matches of the given request path. 如果要求路徑以指定路徑為開頭,則會執行分支。If the request path starts with the given path, the branch is executed.

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

下表說明使用上述程式碼後,來自 http://localhost:1234 的要求及回應。The following table shows the requests and responses from http://localhost:1234 using the previous code.

要求Request 回應Response
localhost:1234localhost:1234 Hello from non-Map delegate.Hello from non-Map delegate.
localhost:1234/map1localhost:1234/map1 Map Test 1Map Test 1
localhost:1234/map2localhost:1234/map2 Map Test 2Map Test 2
localhost:1234/map3localhost:1234/map3 Hello from non-Map delegate.Hello from non-Map delegate.

使用 Map 時,會將相符的路徑線段從 HttpRequest.Path 移除,並附加至每個要求的 HttpRequest.PathBaseWhen Map is used, the matched path segments are removed from HttpRequest.Path and appended to HttpRequest.PathBase for each request.

MapWhen 會依據指定述詞的結果將要求管線分支。MapWhen branches the request pipeline based on the result of the given predicate. Func<HttpContext, bool> 類型的任何述詞皆可用來將要求對應至管線的新分支。Any predicate of type Func<HttpContext, bool> can be used to map requests to a new branch of the pipeline. 下列範例會使用述詞來偵測查詢字串變數 branch 是否存在:In the following example, a predicate is used to detect the presence of a query string variable 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. <p>");
        });
    }
}

下表說明使用上述程式碼後,來自 http://localhost:1234 的要求及回應。The following table shows the requests and responses from http://localhost:1234 using the previous code.

要求Request 回應Response
localhost:1234localhost:1234 Hello from non-Map delegate.Hello from non-Map delegate.
localhost:1234/?branch=masterlocalhost:1234/?branch=master Branch used = masterBranch used = master

Map 支援巢狀項目,例如:Map supports nesting, for example:

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

Map 也可以一次比對多個線段:Map can also match multiple segments at once:

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

內建的中介軟體Built-in middleware

ASP.NET Core 隨附下列中介軟體元件。ASP.NET Core ships with the following middleware components. 「順序」 欄說明 中介軟體在要求處理管線中的位置,以及中介軟體可終止要求處理的情況。The Order column provides notes on middleware placement in the request processing pipeline and under what conditions the middleware may terminate request processing. 當中介軟體將要求處理管線短路並防止接下來的下游中介軟體處理要求時,這就是所謂的「終端中介軟體」 。When a middleware short-circuits the request processing pipeline and prevents further downstream middleware from processing a request, it's called a terminal middleware. 如需詳細資訊,請參閱使用 IApplicationBuilder 建立中介軟體管線For more information on short-circuiting, see the Create a middleware pipeline with IApplicationBuilder section.

中介軟體Middleware 說明Description 順序Order
驗證Authentication 提供驗證支援。Provides authentication support. 在需要 HttpContext.User 之前。Before HttpContext.User is needed. OAuth 回呼的終端機。Terminal for OAuth callbacks.
Cookie 原則Cookie Policy 追蹤使用者對用於儲存個人資訊的同意,並強制執行 Cookie 欄位的最低標準,例如 secureSameSiteTracks consent from users for storing personal information and enforces minimum standards for cookie fields, such as secure and SameSite. 在發出 Cookie 的中介軟體之前。Before middleware that issues cookies. 例如:驗證、工作階段、MVC (TempData)。Examples: Authentication, Session, MVC (TempData).
CORSCORS 設定跨原始來源資源共用。Configures Cross-Origin Resource Sharing. 在使用 CORS 的元件之前。Before components that use CORS.
例外狀況處理Exception Handling 處理例外狀況。Handles exceptions. 在產生錯誤的元件之前。Before components that generate errors.
轉送標頭Forwarded Headers 將設為 Proxy 的標頭轉送到目前要求。Forwards proxied headers onto the current request. 在使用更新方法的欄位之前。Before components that consume the updated fields. 範例:配置、主機,用戶端 IP、方法。Examples: scheme, host, client IP, method.
健康狀態檢查Health Check 檢查 ASP.NET Core 應用程式及其相依性的健康狀態,例如檢查資料庫可用性。Checks the health of an ASP.NET Core app and its dependencies, such as checking database availability. 若某項要求與健康狀態檢查端點相符,則會是終端機。Terminal if a request matches a health check endpoint.
HTTP 方法覆寫HTTP Method Override 允許傳入的 POST 要求覆寫方法。Allows an incoming POST request to override the method. 在使用更新方法的元件之前。Before components that consume the updated method.
HTTPS 重新導向HTTPS Redirection 將所有 HTTP 要求都重新導向至 HTTPS。Redirect all HTTP requests to HTTPS. 在使用 URL 的元件之前。Before components that consume the URL.
HTTP 嚴格的傳輸安全性 (HSTS)HTTP Strict Transport Security (HSTS) 增強安全性的中介軟體,可新增特殊的回應標頭。Security enhancement middleware that adds a special response header. 在傳送回應前和修改要求的元件後。Before responses are sent and after components that modify requests. 例如:轉送的標頭、URL 重寫。Examples: Forwarded Headers, URL Rewriting.
MVCMVC 使用 MVC/Razor 頁面處理要求。Processes requests with MVC/Razor Pages. 若要求符合路由則終止。Terminal if a request matches a route.
OWINOWIN 以 OWIN 為基礎之應用程式、伺服器和中介軟體的 Interop。Interop with OWIN-based apps, servers, and middleware. 若 OWIN 中介軟體完全處理要求則終止。Terminal if the OWIN Middleware fully processes the request.
回應快取Response Caching 提供快取回應的支援。Provides support for caching responses. 在需要快取的元件之前。Before components that require caching.
回應壓縮Response Compression 提供壓縮回應的支援。Provides support for compressing responses. 在需要壓縮的元件之前。Before components that require compression.
要求當地語系化Request Localization 提供當地語系化支援。Provides localization support. 在偵測當地語系化的元件之前。Before localization sensitive components.
路由傳送Routing 定義並限制要求路由。Defines and constrains request routes. 比對路由的終端機。Terminal for matching routes.
工作階段Session 提供管理使用者工作階段的支援。Provides support for managing user sessions. 在需要工作階段的元件之前。Before components that require Session.
靜態檔案Static Files 支援靜態檔案的提供和目錄瀏覽。Provides support for serving static files and directory browsing. 若要求符合檔案則終止。Terminal if a request matches a file.
URL 重寫URL Rewriting 提供重寫 URL 及重新導向要求的支援。Provides support for rewriting URLs and redirecting requests. 在使用 URL 的元件之前。Before components that consume the URL.
WebSocketsWebSockets 啟用 WebSockets 通訊協定。Enables the WebSockets protocol. 在接受 WebSocket 要求的必要元件之前。Before components that are required to accept WebSocket requests.

其他資源Additional resources