当前位置: 首页 > 知识库问答 >
问题:

如何在java中将数据从grpc rpc调用传递到服务器拦截器

辛建业
2023-03-14

我试图在处理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调用中做到这一点。所以我试图使用服务器拦截器。

有人能帮忙吗?

共有1个答案

慕兴平
2023-03-14

您可以使用grpc-java的Contexts。在拦截器中,您附加了一个带有包含可变引用的自定义键的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), 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\u HOLDER\u键即可。get()。放(…)

 类似资料:
  • 我一直在阅读Struts2文档中的,它讨论了如何将StoreInterceptor添加到中的操作定义中,并且它很管用。但如果您要从操作中创建和添加,则情况就是如此。 我的问题是,我正在使用进行登录,如果登录失败,它将添加一个,如下所示: 它添加得很好,但当我进入在之后调用的LoginAction时,为。 我认为通过像这样添加,它将在请求或会话中存储(使用或参数): 但不管用。我还尝试将直接添加到d

  • 问题内容: 我有以下控制器: 我想将绑定的ng模型传递给以下服务,该模型位于我的视图中… 如何连接控制器的作用域以传递到服务中?谢谢! 问题答案: 如何在angularjs中将范围从控制器传递到服务? 您不能将$ scope注入服务,没有像Singleton $ scope这样的东西。 我想将绑定的ng模型传递给以下服务,该模型位于我的视图中,即ng-model =“ symbol_wanted”

  • 我是spring的新手,在spring3中创建了一个应用程序。0我正在使用注释spring。 我想从我的控制器方法返回列表到jsp。列表将显示在选择框中。以下是控制器和jsp部分的代码。请帮助我理解这一点。 和JSP 在模型中添加用户时,它工作正常,但是当我添加lookingfor属性时。model.add属性(“lookingfor”,lookingfor); 这是一个错误。 严重:Servle

  • 问题内容: 我想在Java-SE应用程序中使用拦截器,并且将weld作为CDI实现,并且在这里进行测试: 主班: 服务等级: 拦截器类: Aaa和输出: 我的问题 第一:为什么我在调用methodCallNumberTwo()时没有在methodCall()中调用拦截器? 第二:有办法改变吗? 我仅研究拦截器的行为,并且想了解。先感谢您! 问题答案: 不会调用拦截器,因为您是在对象的同一实例上调用

  • 我正在通过JRuby运行一个本地Rails服务器(WEBrick),并想测试一些最终将在Torquebox上运行的代码。我试图通过访问一些定制的Java系统属性。在Torquebox上运行时,这些系统属性将可用,因此为了在本地测试代码,我使用“-J”参数在命令行上传递系统属性 当我运行JRuby时,一切正常,我可以访问我的自定义属性。 这只是打印“my_value”来输出。 我的问题是在运行本地R

  • 我创建了一个单独的服务生成器类,如下所示:https://futurestud.io/tutorials/retorfit-2-manage-request-headers-in-okhttp-interceptor apiserviceGenerator.java