gRPC 拦截器是一种强大的功能,用于在 gRPC 调用过程中对请求和响应进行拦截、修改和监视。拦截器允许你在请求和响应被发送和接收之前或之后插入自定义逻辑,从而实现各种功能,如认证、授权、日志记录、错误处理等。拦截器可以在客户端和服务器两端使用,它们是实现横切关注点的一种重要方式。
使用场景
- 认证和授权: 使用拦截器可以实现认证和授权逻辑。在拦截器中,你可以验证请求的身份、权限等信息,并根据情况决定是否允许请求继续进行。
- 日志记录: 拦截器可以用于记录请求和响应的详细信息,从而实现日志记录和监控。你可以记录请求的内容、调用的方法、响应的结果等,以便于调试和分析。
- 错误处理: 在拦截器中可以捕获和处理 gRPC 调用过程中可能发生的错误,以提供更友好的错误信息或进行恢复操作。
- 性能监视: 使用拦截器可以监视 gRPC 调用的性能指标,如调用时间、响应时间等,从而实现性能监控和优化。
- 传输层安全: 拦截器可以用于添加和处理传输层安全(TLS)相关的信息,如证书、密钥等。
代码实现
gRPC拦截器分为两种,即客户端拦截器和服务端拦截器,我们现在通过这两种拦截器来实现日志记录
服务端拦截器
代码语言:javascript复制public class ServerLoggingInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
Metadata headers, ServerCallHandler<ReqT, RespT> next) {
System.out.println("Received request: " call.getMethodDescriptor().getFullMethodName());
ServerCall.Listener<ReqT> listener = next.startCall(call, headers);
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(listener) {
@Override
public void onMessage(ReqT message) {
System.out.println("Received message: " message.toString());
super.onMessage(message);
}
@Override
public void onHalfClose() {
System.out.println("Client closed the call.");
super.onHalfClose();
}
@Override
public void onCancel() {
System.out.println("Call cancelled by client.");
super.onCancel();
}
@Override
public void onComplete() {
System.out.println("Call completed.");
super.onComplete();
}
};
}
配置服务端拦截器
代码语言:javascript复制public class HelloServer {
public static void main(String[] args) throws Exception {
Server server = ServerBuilder.forPort(9090)
.addService(new HelloServiceIpl())
.intercept(new ServerLoggingInterceptor())
.build();
server.start();
System.out.println("gRPC服务启动");
server.awaitTermination();
}
}
客户端拦截器
代码语言:javascript复制public class ClientLoggingInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions, Channel next) {
System.out.println("Sending request: " method.getFullMethodName());
// 创建一个客户端调用,传递给下一个拦截器或通道
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
// 在调用开始前执行操作
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onMessage(RespT message) {
// 处理接收到的响应消息
System.out.println("Received response: " message.toString());
super.onMessage(message);
}
}, headers);
}
};
}
}
配置客户端拦截器
代码语言:javascript复制ManagedChannel channel = ManagedChannelBuilder
.forAddress("localhost", 9090)
.usePlaintext()
.intercept(new ClientLoggingInterceptor())
.build();