注意
這不是這篇文章的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 關於目前版本,請參閱 本文的 .NET 10 版本。
攔截器是一種 gRPC 概念,可讓應用程式與傳入或傳出的 gRPC 呼叫互動。 其可提供擴充要求處理管線的方式。
攔截器會針對通道或服務進行設定,並針對每個 gRPC 呼叫自動執行。 由於攔截器對於使用者的應用程式邏輯而言是透明的,因此它們是常見案例 (例如,記錄、監視、驗證及驗證) 的絕佳解決方案。
Interceptor 類型
藉由建立繼承自 Interceptor 類型的類別,可為 gRPC 伺服器和用戶端實作攔截器:
public class ExampleInterceptor : Interceptor
{
}
根據預設,Interceptor 基底類別不會執行任何動作。 透過在攔截器實作中覆寫適當的基底類別方法,將功能或行為新增至攔截器。
用戶端攔截器
gRPC 用戶端攔截器會攔截傳出的 RPC 調用。 其提供對已傳送要求、傳入回應及用戶端呼叫內容的存取權。
要針對用戶端覆寫的 Interceptor 方法:
-
BlockingUnaryCall:攔截一元 RPC 的封鎖調用。 -
AsyncUnaryCall:攔截一元 RPC 的非同步叫用。 -
AsyncClientStreamingCall:攔截用戶端串流 RPC 的非同步叫用。 -
AsyncServerStreamingCall:攔截伺服器串流 RPC 的非同步調用。 -
AsyncDuplexStreamingCall:攔截雙向串流 RPC 的非同步叫用。
警告
雖然 BlockingUnaryCall 和 AsyncUnaryCall 都是指一元 RPC,但二者無法互換。
AsyncUnaryCall 不會攔截封鎖叫用,而 BlockingUnaryCall 不會攔截非同步叫用。
建立用戶端 gRPC 攔截器
下列程式碼提供攔截一元呼叫之非同步叫用的基本範例:
public class ClientLoggingInterceptor : Interceptor
{
private readonly ILogger _logger;
public ClientLoggingInterceptor(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<ClientLoggingInterceptor>();
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
_logger.LogInformation("Starting call. Type/Method: {Type} / {Method}",
context.Method.Type, context.Method.Name);
return continuation(request, context);
}
}
覆寫 AsyncUnaryCall:
- 攔截非同步的單一呼叫。
- 記錄呼叫的詳細資料。
- 呼叫傳入方法的
continuation參數。 如果這是最後一個攔截器,則會叫用鏈結中的下一個攔截器或基礎呼叫啟動程式。
對於每種服務方法,Interceptor 上的方法都有不同的簽章。 不過,continuation 和 context 參數背後的概念保持不變:
-
continuation是委派,可叫用鏈結中的下一個攔截器或基礎呼叫啟動程式 (如果鏈結中沒有任何攔截器)。 呼叫零次或多次並不是錯誤。 攔截器不需要傳回從AsyncUnaryCall委派傳回的呼叫表示法 (如果是一元 RPC,則為continuation)。 省略委派呼叫並回傳您自己的呼叫表示法實例,將中斷攔截器的鏈結,並即時回傳相關的回應。 -
context包含與用戶端呼叫相關聯的範圍值。 請使用context來傳遞中繼資料,例如安全性主體、認證或追蹤資料。 此外,context還包含期限和取消的相關資訊。 如需詳細資訊,請參閱具有期限和取消功能的可靠 gRPC 服務。
在用戶端攔截器中等候回應
攔截器可以藉由更新 AsyncUnaryCall<TResponse>.ResponseAsync 或 AsyncClientStreamingCall<TRequest, TResponse>.ResponseAsync 值,等候一元和用戶端串流呼叫中的回應。
public class ErrorHandlerInterceptor : Interceptor
{
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(
HandleResponse(call.ResponseAsync),
call.ResponseHeadersAsync,
call.GetStatus,
call.GetTrailers,
call.Dispose);
}
private async Task<TResponse> HandleResponse<TResponse>(Task<TResponse> inner)
{
try
{
return await inner;
}
catch (Exception ex)
{
throw new InvalidOperationException("Custom error", ex);
}
}
}
上述 程式碼:
- 創建一個可以取代
AsyncUnaryCall的新攔截器。 - 覆寫
AsyncUnaryCall:- 呼叫
continuation參數以叫用攔截器鏈結中的下一個項目。 - 根據接續的結果建立新的
AsyncUnaryCall<TResponse>執行個體。 - 使用
ResponseAsync方法包裝HandleResponse工作。 - 使用
HandleResponse等候回應。 等候回應允許在用戶端收到回應之後新增邏輯。 透過在 try-catch 區塊中等候回應,即可記錄來自呼叫的錯誤。
- 呼叫
如需如何建立用戶端攔截器的詳細資訊,請參閱 ClientLoggerInterceptor.cs GitHub 存放庫中的 grpc/grpc-dotnet 範例。
設定用戶端攔截器
gRPC 用戶端攔截器是在頻道上設定。
下列程式碼範例:
- 使用
GrpcChannel.ForAddress建立通道。 - 使用
Intercept擴充方法將通道設定為使用攔截器。 請注意,這個方法會傳回CallInvoker。 強型別 gRPC 用戶端可以像通道一樣從調用器建立。 - 從啟動程式建立用戶端。 用戶端所發出的 gRPC 呼叫會自動執行攔截器。
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientLoggerInterceptor());
var client = new Greeter.GreeterClient(invoker);
可以鏈結 Intercept 擴充方法,為通道設定多個攔截器。 或者,使用一個可接受多個攔截器的 Intercept 多載。 您可以針對單一 gRPC 呼叫執行任意數目的攔截器,如下列範例所示:
var invoker = channel
.Intercept(new ClientTokenInterceptor())
.Intercept(new ClientMonitoringInterceptor())
.Intercept(new ClientLoggerInterceptor());
攔截器會依鏈結 Intercept 擴充方法的反向順序叫用。 在上述程式碼中,攔截器會依下列順序叫用:
ClientLoggerInterceptorClientMonitoringInterceptorClientTokenInterceptor
如需如何使用 gRPC 用戶端處理站設定攔截器的資訊,請參閱 .NET 中的 gRPC 用戶端處理站整合。
伺服器攔截器
gRPC 伺服器攔截器可攔截傳入的 RPC 要求。 其提供對傳入要求、傳出回應及伺服器端呼叫內容的存取權。
要針對伺服器覆寫的 Interceptor 方法:
-
UnaryServerHandler:攔截一元 RPC。 -
ClientStreamingServerHandler:攔截用戶端串流 RPC。 -
ServerStreamingServerHandler:攔截伺服器串流 RPC。 -
DuplexStreamingServerHandler:攔截雙向串流 RPC。
建立 gRPC 伺服器攔截器
下列程式碼展示了攔截傳入的一元 RPC 的範例:
public class ServerLoggerInterceptor : Interceptor
{
private readonly ILogger _logger;
public ServerLoggerInterceptor(ILogger<ServerLoggerInterceptor> logger)
{
_logger = logger;
}
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
_logger.LogInformation("Starting receiving call. Type/Method: {Type} / {Method}",
MethodType.Unary, context.Method);
try
{
return await continuation(request, context);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error thrown by {context.Method}.");
throw;
}
}
}
覆寫 UnaryServerHandler:
- 攔截傳入的一元呼叫。
- 記錄呼叫的詳細資料。
- 呼叫傳入方法的
continuation參數。 如果這是最後一個攔截器,則會叫用鏈結中的下一個攔截器或服務處理常式。 - 記錄任何例外狀況。 等候接續允許在執行服務方法之後新增邏輯。 透過在 try-catch 區塊中等候接續,即可記錄來自方法的錯誤。
用戶端與伺服器攔截器方法的簽章類似:
-
continuation代表傳入 RPC 的代理人,其負責呼叫鏈結中的下一個攔截器或服務處理器(如果鏈結中沒有任何攔截器)。 與用戶端攔截器類似,您可以隨時進行呼叫,而無需直接從接續委派傳回回應。 透過等候接續,即可在執行服務處理常式之後新增輸出邏輯。 -
context包含與伺服器端呼叫相關聯的中繼資料,例如請求中繼資料、期限、取消或 RPC 結果。
如需如何建立伺服器攔截器的詳細資訊,請參閱 ServerLoggerInterceptor.cs GitHub 存放庫中的 grpc/grpc-dotnet 範例。
設定伺服器攔截器
gRPC 伺服器攔截器是在啟動時設定。 下列程式碼範例:
- 使用
AddGrpc將 gRPC 新增至應用程式。 - 透過將
ServerLoggerInterceptor新增至服務選項的Interceptors集合,為所有服務設定該項目。
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});
}
您也可以使用 AddServiceOptions 並指定服務類型,為特定服務設定攔截器。
public void ConfigureServices(IServiceCollection services)
{
services
.AddGrpc()
.AddServiceOptions<GreeterService>(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});
}
攔截器會依其新增至 InterceptorCollection 的順序執行。 如果已設定全域和單一服務攔截器,則會先執行全域設定的攔截器,再執行針對單一服務設定的攔截器。
預設情況下,gRPC 伺服器的攔截器在每個請求的存活期內運作。 透過使用相依性插入註冊攔截器類型,就可以覆寫此行為。 下列範例會註冊 ServerLoggerInterceptor 的單一資料庫存留期:
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerLoggerInterceptor>();
});
services.AddSingleton<ServerLoggerInterceptor>();
}
gRPC 攔截器與中介軟體
相較於 C-core 型 gRPC 應用程式中的攔截器,ASP.NET Core 中介軟體提供類似的功能。 ASP.NET Core 中介軟體和攔截器在概念上相似。 兩個都:
- 用來建構處理 gRPC 請求的管線。
- 允許在管線的下一個元件之前或之後執行工作。
- 提供
HttpContext的存取權:- 在中介軟體中,
HttpContext是參數。 - 在攔截器中,可以使用
HttpContext參數搭配ServerCallContext擴充方法來存取ServerCallContext.GetHttpContext。 這項功能專屬於在 ASP.NET Core 中執行的攔截器。
- 在中介軟體中,
gRPC 攔截器與 ASP.NET Core 中介軟體的差異:
- 攔截器:
- 使用
ServerCallContext在 gRPC 抽象層上操作。 - 提供下列項目的存取權:
- 傳送至呼叫的還原序列化訊息。
- 序列化之前,訊息是從呼叫中傳回的。
- 可以擷取並處理從 gRPC 服務擲回的例外狀況。
- 使用
- 中介軟體:
- 針對所有 HTTP 要求執行。
- 在 gRPC 攔截器之前執行。
- 對基礎 HTTP/2 訊息進行操作。
- 只能存取要求和回應串流中的位元組。