绕过特定端点的 gRPC 拦截器
Bypass gRPC interceptor for specific endpoint
最近我一直在为一个问题而苦苦挣扎:我不能忽略某些端点的 io.grpc.ServerInterceptor
,在我的例子中是健康检查端点,由 io.grpc.protobuf.services.HealthServiceImpl
[=14 提供=]
我能找到的唯一选择是定义一个新的 ServerInterceptor,它通过 io.grpc.Listener#onMessage
检索端点名称,如果端点匹配,则在执行任何其他 ServerInteceptor 之前关闭 gRPC 调用。
不过,这个方案看起来不是很优雅。
有没有办法(也许是通过配置)忽略我现有的拦截器?
这个问题是新问题,当我开始使用 gRPC 版本 1.42.2 时。在 gRPC 1.35.0.
下一切正常
感谢您的帮助。
编辑:一些代码
在我的配置中 class :
@Bean
HealthStatusManager healthStatusManager() {
return new HealthStatusManager();
}
@Bean
Server server(
Service1 service1,
Service2 service2,
HealthStatusManager healthStatusManager
) {
return ServerBuilder.forPort(9090)
.addService(service1)
.addService(service2)
.addService(healthStatusManager.getHealthService())
// I do not want these to interceptors to be executed for healthService
.intercept(new Interceptor1())
.intercept(new Interceptor2())
.build();
}
Interceptor2 做了一些我的健康检查服务不需要的检查(甚至阻止它正常工作)
Protobuf/gRPC 反射在这种情况下可能很有用。我将通过执行以下操作来实现这样的解决方案:
假设我有以下服务:
service HealthService {
//...
}
会生成一个 HealthServiceGrpc
class 并且在这个 class 中有一个 public static final String SERVICE_NAME
(请注意,如果您使用 java gRPC 的精简版可能不存在).
在那之后,您在 ServerInterceptor.interceptCall
中的 ServerCall
class 具有 getMethodDescriptor()
功能。这 returns 您正在调用的端点的描述符。从中您可以获得服务名称。尽管如此,一个基本的实现是:
public class Interceptor1 implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
if (Objects.equals(call.getMethodDescriptor().getServiceName(), HealthServiceGrpc.SERVICE_NAME))
return next.startCall(call, headers);
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(next.startCall(call, headers)) {
//...
};
}
}
在这里稍微解释一下,如果服务的名称是HealthService,我们就直接调用,否则我们通过拦截器实现。
显然,在那之后,如果你想要更少的手动操作,你可能想要使用一个 Singleton 实例,它注册哪个拦截器来跳过哪个服务。
我们遇到了同样的问题,但做了一些我觉得更简单的不同事情。
在您的 Server Builder 中,您可以将拦截器附加到特定端点,如下所示:
@Bean
HealthStatusManager healthStatusManager() {
return new HealthStatusManager();
}
@Bean
Server server(
Service1 service1,
Service2 service2,
HealthStatusManager healthStatusManager
) {
return ServerBuilder.forPort(9090)
.addService(ServerInterceptor.intercept(service1, new Interceptor1(), new Interceptor2()))
.addService(ServerInterceptor.intercept(service2, new Interceptor1(), new Interceptor2()))
.addService(healthStatusManager.getHealthService())
.build();
}
希望这对您有用!
最近我一直在为一个问题而苦苦挣扎:我不能忽略某些端点的 io.grpc.ServerInterceptor
,在我的例子中是健康检查端点,由 io.grpc.protobuf.services.HealthServiceImpl
[=14 提供=]
我能找到的唯一选择是定义一个新的 ServerInterceptor,它通过 io.grpc.Listener#onMessage
检索端点名称,如果端点匹配,则在执行任何其他 ServerInteceptor 之前关闭 gRPC 调用。
不过,这个方案看起来不是很优雅。 有没有办法(也许是通过配置)忽略我现有的拦截器?
这个问题是新问题,当我开始使用 gRPC 版本 1.42.2 时。在 gRPC 1.35.0.
下一切正常感谢您的帮助。
编辑:一些代码
在我的配置中 class :
@Bean
HealthStatusManager healthStatusManager() {
return new HealthStatusManager();
}
@Bean
Server server(
Service1 service1,
Service2 service2,
HealthStatusManager healthStatusManager
) {
return ServerBuilder.forPort(9090)
.addService(service1)
.addService(service2)
.addService(healthStatusManager.getHealthService())
// I do not want these to interceptors to be executed for healthService
.intercept(new Interceptor1())
.intercept(new Interceptor2())
.build();
}
Interceptor2 做了一些我的健康检查服务不需要的检查(甚至阻止它正常工作)
Protobuf/gRPC 反射在这种情况下可能很有用。我将通过执行以下操作来实现这样的解决方案:
假设我有以下服务:
service HealthService {
//...
}
会生成一个 HealthServiceGrpc
class 并且在这个 class 中有一个 public static final String SERVICE_NAME
(请注意,如果您使用 java gRPC 的精简版可能不存在).
在那之后,您在 ServerInterceptor.interceptCall
中的 ServerCall
class 具有 getMethodDescriptor()
功能。这 returns 您正在调用的端点的描述符。从中您可以获得服务名称。尽管如此,一个基本的实现是:
public class Interceptor1 implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
if (Objects.equals(call.getMethodDescriptor().getServiceName(), HealthServiceGrpc.SERVICE_NAME))
return next.startCall(call, headers);
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(next.startCall(call, headers)) {
//...
};
}
}
在这里稍微解释一下,如果服务的名称是HealthService,我们就直接调用,否则我们通过拦截器实现。
显然,在那之后,如果你想要更少的手动操作,你可能想要使用一个 Singleton 实例,它注册哪个拦截器来跳过哪个服务。
我们遇到了同样的问题,但做了一些我觉得更简单的不同事情。
在您的 Server Builder 中,您可以将拦截器附加到特定端点,如下所示:
@Bean
HealthStatusManager healthStatusManager() {
return new HealthStatusManager();
}
@Bean
Server server(
Service1 service1,
Service2 service2,
HealthStatusManager healthStatusManager
) {
return ServerBuilder.forPort(9090)
.addService(ServerInterceptor.intercept(service1, new Interceptor1(), new Interceptor2()))
.addService(ServerInterceptor.intercept(service2, new Interceptor1(), new Interceptor2()))
.addService(healthStatusManager.getHealthService())
.build();
}
希望这对您有用!