gRPC拦截器类型
| 类型 | 作用 | 注册方式 |
| ServerInterceptor | 服务端拦截请求/响应 | ServerBuilder.intercept() |
| ClientInterceptor | 客户端拦截请求/响应 | ManagedChannelBuilder.intercept() |
服务端拦截器示例
public class AuthInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
// 提取JWT Token
String authHeader = headers.get(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER));
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
call.close(Status.UNAUTHENTICATED.withDescription("缺少Token"), new Metadata());
return new ServerCall.Listener<>() {};
}
String token = authHeader.substring(7);
try {
// 验证JWT
Claims claims = Jwts.parser().verifyWith(publicKey).build().parseSignedClaims(token).getPayload();
Context ctx = Context.current().withValue(USER_ID_KEY, claims.getSubject());
return Contexts.interceptCall(ctx, call, headers, next);
} catch (Exception e) {
call.close(Status.UNAUTHENTICATED.withDescription("Token无效"), new Metadata());
return new ServerCall.Listener<>() {};
}
}
}
客户端拦截器示例
public class LoggingInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override
public void sendMessage(ReqT message) {
log.info("发送请求: {} {}", method.getFullMethodName(), message);
super.sendMessage(message);
}
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onMessage(RespT message) {
log.info("收到响应: {}", message);
super.onMessage(message);
}
}, headers);
}
};
}
}
注册拦截器
// 服务端
Server server = ServerBuilder.forPort(50051)
.addService(ServerInterceptors.intercept(userService,
new AuthInterceptor(), new LoggingInterceptor(), new RateLimitInterceptor()))
.build();
// 客户端
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
.intercept(new AuthClientInterceptor(token), new LoggingInterceptor())
.usePlaintext()
.build();
与Spring MVC Interceptor对比
| 维度 | gRPC Interceptor | Spring MVC Interceptor |
| 触发时机 | 方法调用前后(gRPC Call) | HTTP请求前后 |
| 上下文传递 | Context(ThreadLocal替代方案) | Request Attributes |
| 流式处理 | 可拦截消息级别 | 无流式概念 |
| 元数据 | Metadata(类似HTTP Headers) | HttpServletRequest/Response |