共用方式為


YARP 中間件

介紹

ASP.NET Core 會使用 中間件管線 將要求處理分割成離散步驟。 應用程式開發人員可以視需要新增及訂購中間件。 ASP.NET Core 中間件也可用來實作和自定義反向 Proxy 功能。

違約

用戶入門 範例顯示下列 Configure 方法。 這會設定中間件管線,其中包含開發工具、路由和 Proxy 設定的端點 (MapReverseProxy)。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();

MapReverseProxy() 多載中的無參數 包含針對 會話親和性負載平衡被動健康檢查 和請求的最終代理的所有標準代理中介軟體。 每一項都會檢查相符路由、叢集和目的地的組態,並據以執行其工作。

新增中間件

新增至應用程式管線的中間件會根據其所在位置,以不同的處理階段來檢視請求。 在 UseRouting 之前新增的中間件可以看到所有請求,並且可以在進行任何路由之前對它們進行操作。 在 UseRoutingUseEndpoints 之間新增的中間件可以呼叫 HttpContext.GetEndpoint(),以檢查哪個端點路由符合要求(如果有的話),並使用與該端點相關聯的任何元數據。 這就是如何處理 驗證與授權 以及 CORS

ReverseProxyIEndpointRouteBuilderExtensions 提供了 MapReverseProxy 的多載,使您可以建置一條中介軟體管線,該管線僅針對符合由 Proxy 設定的路由的要求進行執行。

app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use((context, next) =>
    {
        // Custom inline middleware

        return next();
    });
    proxyPipeline.UseSessionAffinity();
    proxyPipeline.UseLoadBalancing();
    proxyPipeline.UsePassiveHealthChecks();
});

根據預設,這個 MapReverseProxy 多載只會包含管線開頭和結尾的最小設定、Proxy 處理邏輯,以及限制強制執行。 會話親和性、負載平衡和被動健康情況檢查的中間件預設不包含,因此您可以使用任何其他中間件來排除、取代或控制其排序。

自訂 Proxy 中間件

MapReverseProxy 管線內的中間件可透過 IReverseProxyFeature,存取與要求相關聯的所有 Proxy 數據和狀態(路由、叢集、目的地等)。 您可以從 HttpContext.Features 或擴充方法 HttpContext.GetReverseProxyFeature()取得。

IReverseProxyFeature 中的資料是從代理伺服器管道開始時的代理組態中拍攝的快照,且在請求處理過程中發生的代理組態變更不會影響這些資料。

proxyPipeline.Use((context, next) =>
{
    var proxyFeature = context.GetReverseProxyFeature();
    var cluster = proxyFeature.Cluster;
    var destinations = proxyFeature.AvailableDestinations;

    return next();
});

如何處理中間件

中間件可以產生記錄、控制要求是否受到 Proxy 處理、影響其代理位置,以及新增其他功能,例如錯誤處理、重試等等。

記錄和計量

中間件可以檢查要求和回應欄位,以產生記錄和匯總計量。 請參閱下方「中間件的禁忌事項」中的內容附註。

proxyPipeline.Use(async (context, next) =>
{
    LogRequest(context);
    await next();
    LogResponse(context);
});

立刻回覆

如果中間件檢查要求並判斷它不應該進行 Proxy 處理,它可能會產生自己的回應,並將控制權傳回伺服器,而不呼叫 next()

proxyPipeline.Use((context, next) =>
{
    if (!CheckAllowedRequest(context, out var reason))
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        return context.Response.WriteAsync(reason);
    }

    return next();
});

篩選目的地

會話親和性和負載平衡等中間件會檢查 IReverseProxyFeature 和叢集組態,以決定應傳送要求的目標目的地。

AllDestinations 會列出所選叢集中的所有目的地。

AvailableDestinations 列出目前視為可處理要求的目的地。 它會初始化為 AllDestinations,如果啟用了健康檢查,則排除不健康的。 AvailableDestinations 應該在管線結束時簡化為一個單一目的地,否則將從剩餘的目的地中隨機選擇一個。

ProxiedDestination 是由管線結尾的代理邏輯所設定,以指出最終使用哪一個目的地。 如果沒有可用的目的地剩餘,則會傳送 503 錯誤回應。

proxyPipeline.Use(async (context, next) =>
{
    var proxyFeature = context.GetReverseProxyFeature();
    proxyFeature.AvailableDestinations = Filter(proxyFeature.AvailableDestinations);

    await next();

    Report(proxyFeature.ProxiedDestination);
});

DestinationState 會實作 IReadOnlyList<DestinationState>,以便將單一目的地指派給 AvailableDestinations,而不需要建立新的清單。

錯誤處理

中間件可以在 try/catch 區塊中包裝對 await next() 的呼叫,以處理後續元件的例外狀況。

管線結尾的代理邏輯 (IHttpForwarder) 不會針對常見的請求代理錯誤擲回例外狀況。 這些會被擷取並報告在 IForwarderErrorFeature,可從 HttpContext.FeaturesHttpContext.GetForwarderErrorFeature() 擴充方法中取得。

proxyPipeline.Use(async (context, next) =>
{
    await next();

    var errorFeature = context.GetForwarderErrorFeature();
    if (errorFeature is not null)
    {
        Report(errorFeature.Error, errorFeature.Exception);
    }
});

如果回應尚未開始(HttpResponse.HasStarted),則可以清除(HttpResponse.Clear())並傳送替代回應,或者重設代理功能欄位並重試請求。

中間件不應該做的事

中間件應該謹慎修改請求欄位,例如標頭,以影響到傳出的代理請求。 這類修改可能會干擾重試等功能,並且由 轉換處理得更好。

中間件必須在呼叫 HttpResponse.HasStarted之後,先檢查 next(),再修改回應字段。 如果回應已開始傳送至用戶端,則中間件無法再修改它(可能為 「預告片」除外)。 轉換 可用來檢查和抑制不必要的回應。 否則,請參閱下一個附注。

中間件應該避免與要求或響應主體互動。 物件預設不會進行緩衝,因此與其互動可能會防止它們到達目的地。 雖然可以啟用緩衝處理,但不建議使用,因為它可能會增加顯著的記憶體和延遲額外負荷。 如果必須檢查或修改內容,建議使用包裝的串流方法。 如需範例,請參閱 ResponseCompression 中間件。

中間件不得對個別要求執行任何多線程工作,HttpContext 及其相關聯的成員不是安全線程。