介紹
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
之前新增的中間件可以看到所有請求,並且可以在進行任何路由之前對它們進行操作。 在 UseRouting
和 UseEndpoints
之間新增的中間件可以呼叫 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.Features
或 HttpContext.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
及其相關聯的成員不是安全線程。