如何在Java中将数据从grpc rpc调用传递到服务器拦截器 [英] How to pass data from grpc rpc call to server interceptor in java
问题描述
在处理rpc服务器调用之后,我尝试使用响应中的值设置一些元数据.计划是使用服务器拦截器并覆盖 close
方法.
I am trying to set some metadata with a value from the response after the rpc server call has been processed. The plan was to use server interceptor and override close
method.
类似这样的内容:由于元数据值取决于响应,因此我需要某种方式将数据从rpc服务器调用传递到服务器拦截器,或从拦截器访问响应
Since the metadata value depends on the response, I need some way to pass data from rpc server call to server interceptor or access the response from interceptor
在Golang中,处理后可以在rpc调用 grpc.SetTrailer
中轻松设置元数据,但是在Java中,无法在rpc调用中进行设置.因此,我尝试使用服务器拦截器.
In Golang, the metadata can be set easily in the rpc call grpc.SetTrailer
after processing but in java there is no way to do it in rpc call. So I am trying to use server interceptor for the same.
有人可以帮忙吗?
推荐答案
您可以为此使用grpc-java的 Context
.在拦截器中,将 Context
附加到包含可变引用的自定义键.然后在通话中,您再次访问该标头并从中提取值.
You can use grpc-java's Context
s for that.
In the interceptor you attach a Context
with a custom key containing a mutable reference. Then in the call you access that header again and extract the value from it.
public static final Context.Key<TrailerHolder> TRAILER_HOLDER_KEY = Context.key("trailerHolder");
Context context = Context.current().withValue(TRAILER_HOLDER_KEY, new TrailerHolder());
Context previousContext = context.attach();
[...]
context.detach(previousContext);
您可以像这样访问上下文值:
You can access the context value like this:
TrailerHolder trailerHolder = TRAILER_HOLDER_KEY.get();
您可能想要实现类似于以下方法的代码: <代码> Contexts#interceptCall(Context,ServerCall,元数据,ServerCallHandler)
You might want to implement your code similar to this method:
Contexts#interceptCall(Context, ServerCall, Metadata, ServerCallHandler)
import io.grpc.Context;
import io.grpc.ForwardingServerCall.SimpleForwardingServerCall;
import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCall.Listener;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
public class TrailerServerInterceptor implements ServerInterceptor {
public static final Context.Key<Metadata> TRAILER_HOLDER_KEY = Context.key("trailerHolder");
@Override
public <ReqT, RespT> Listener<ReqT> interceptCall(final ServerCall<ReqT, RespT> call, final Metadata headers,
final ServerCallHandler<ReqT, RespT> next) {
final TrailerCall<ReqT, RespT> call2 = new TrailerCall<>(call);
final Context context = Context.current().withValue(TRAILER_HOLDER_KEY, new Metadata());
final Context previousContext = context.attach();
try {
return new TrailerListener<>(next.startCall(call2, headers), context);
} finally {
context.detach(previousContext);
}
}
private class TrailerCall<ReqT, RespT> extends SimpleForwardingServerCall<ReqT, RespT> {
public TrailerCall(final ServerCall<ReqT, RespT> delegate) {
super(delegate);
}
@Override
public void close(final Status status, final Metadata trailers) {
trailers.merge(TRAILER_HOLDER_KEY.get());
super.close(status, trailers);
}
}
private class TrailerListener<ReqT> extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {
private final Context context;
public TrailerListener(final ServerCall.Listener<ReqT> delegate, final Context context) {
super(delegate);
this.context = context;
}
@Override
public void onMessage(final ReqT message) {
final Context previous = this.context.attach();
try {
super.onMessage(message);
} finally {
this.context.detach(previous);
}
}
@Override
public void onHalfClose() {
final Context previous = this.context.attach();
try {
super.onHalfClose();
} finally {
this.context.detach(previous);
}
}
@Override
public void onCancel() {
final Context previous = this.context.attach();
try {
super.onCancel();
} finally {
this.context.detach(previous);
}
}
@Override
public void onComplete() {
final Context previous = this.context.attach();
try {
super.onComplete();
} finally {
this.context.detach(previous);
}
}
@Override
public void onReady() {
final Context previous = this.context.attach();
try {
super.onReady();
} finally {
this.context.detach(previous);
}
}
}
}
在grpc服务方法中,您只需使用 TRAILER_HOLDER_KEY.get().put(...)
In your grpc service method you can simply use TRAILER_HOLDER_KEY.get().put(...)
这篇关于如何在Java中将数据从grpc rpc调用传递到服务器拦截器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!