在处理rpc服务器调用之后,我尝试使用响应中的值设置一些元数据。计划是使用服务器拦截器并覆盖close
方法。
类似这样的内容:https://github.com/dconnelly/grpc-error-example/blob/master/src/main/java/example/Errors.java#L38
由于元数据值取决于响应,因此我需要某种方式将数据从rpc服务器调用传递到服务器拦截器,或从拦截器访问响应
在Golang中,处理后可以在rpc调用grpc.SetTrailer
中轻松设置元数据,但是在Java中,无法在rpc调用中进行设置。所以我尝试使用服务器拦截器。
有人可以帮忙吗?
答案 0 :(得分:3)
您可以为此使用grpc-java的Context
。
在拦截器中,将Context
附加到包含可变引用的自定义键。然后在通话中,您再次访问该标头并从中提取值。
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);
您可以像这样访问上下文值:
TrailerHolder trailerHolder = TRAILER_HOLDER_KEY.get();
您可能想要实现类似于以下方法的代码:
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), previousContext);
} 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(...)