zoukankan      html  css  js  c++  java
  • grpc拦截器

    在grpc的报文中可以增加报文头,用于标注消息的元数据。

    服务端拦截器

    在服务端可以继承ServerInterceptor来实现服务端的拦截器,用于操作报文头:

    public class MyServerInterceptor implements ServerInterceptor {
        //服务端header的key
        static final Metadata.Key<String> CUSTOM_HEADER_KEY =
                Metadata.Key.of("serverHeader", Metadata.ASCII_STRING_MARSHALLER);
    
        @Override
        public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
            //输出客户端传递过来的header
    		System.out.println("header received from client:" + headers);
            
    		return next.startCall(new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
                @Override
                public void sendHeaders(Metadata responseHeaders) {
    				//在返回中增加header
                    responseHeaders.put(CUSTOM_HEADER_KEY, "response");
                    super.sendHeaders(responseHeaders);
                }
            }, headers);
        }
    }
    

    客户端拦截器

    类似的,需要继承ClientInterceptor实现客户端的拦截器

    public class MyClientInterceptor implements ClientInterceptor {
        //客户端header的key
        static final Metadata.Key<String> CUSTOM_HEADER_KEY =
                Metadata.Key.of("clientHeader", Metadata.ASCII_STRING_MARSHALLER);
    
        @Override
        public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
            return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
                @Override
                public void start(Listener<RespT> responseListener, Metadata headers) {
    				//放入客户端的header
                    headers.put(CUSTOM_HEADER_KEY, "request");
                    super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
                        @Override
                        public void onHeaders(Metadata headers) {
                            //输出服务端传递回来的header
                            System.out.println("header received from server:" + headers);
                            super.onHeaders(headers);
                        }
                    }, headers);
                }
            };
        }
    }
    

    调用

    在完成两端的拦截器的代码就需要使用它们了,它们的用法是在客户端channel或服务端的构建过程中将它们注入到对应的客户端/服务端header的key,下面我们在上次代码的基础上进行修改

    //服务端
    public class IntceptorServer {
    
        private int port;
        private Server server;
        public IntceptorServer(int port) throws IOException {
            this.port=port;
            server= ServerBuilder.forPort(port)
    				//将MyServerInterceptor注册到服务端
                    .addService(ServerInterceptors.intercept(new HelloServiceImpl(),new MyServerInterceptor()))
                    .build();
            server.start();
            System.out.println("Server started, listening on " + port );
        }
    
        private void blockUntilShutdown() throws InterruptedException {
            while(true){
                server.awaitTermination();
            }
        }
        public static void main(String[] args) throws Exception {
            (new IntceptorServer(8080)).blockUntilShutdown();
        }
    }
    
    //客户端
    public class InterceporClient {
        static final Metadata.Key<String> ATTCHED_HEADER =
                Metadata.Key.of("attached_header", Metadata.ASCII_STRING_MARSHALLER);
    
        public static void  main(String[] args) throws InterruptedException {
            final ManagedChannel originalChannel = ManagedChannelBuilder.forAddress("127.0.0.1", 8080).usePlaintext(true).build();
    		//将MyClientInterceptor和原有的channel结合,生成包含拦截器的channel
            Channel channel = ClientInterceptors.intercept(originalChannel, new MyClientInterceptor());
            HelloServiceGrpc.HelloServiceBlockingStub blockingStub = HelloServiceGrpc.newBlockingStub(channel);
    
            ProtoObj.Person person = ProtoObj.Person.newBuilder().setMyName("World").build();
            System.out.println(blockingStub.simpleHello(person).getString());
    		
    		//如果只需要在客户端传送header,而不需要接受服务端的header可以简单调用MetadataUtils.attachHeaders注册meta数据而不用定义Interceptor
    		blockingStub = HelloServiceGrpc.newBlockingStub(originalChannel);
            Metadata meta=new Metadata();
            meta.put(ATTCHED_HEADER, "attched");
            HelloServiceGrpc.HelloServiceBlockingStub s=MetadataUtils.attachHeaders(blockingStub,meta);
            System.out.println(s.simpleHello(person).getString());
    		
    		//关闭originalChannel
            originalChannel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    
        }
    }
    
    ----服务端输出----
    header received from client:Metadata(content-type=application/grpc,user-agent=grpc-java-netty/1.2.0,clientheader=request,grpc-accept-encoding=gzip,grpc-census-bin=)
    World calling
    header received from client:Metadata(content-type=application/grpc,user-agent=grpc-java-netty/1.2.0,attached_header=attched,grpc-accept-encoding=gzip,grpc-census-bin=)
    World calling
    
    ----客户端输出----
    header received from server:Metadata(content-type=application/grpc,serverheader=response,grpc-encoding=identity,grpc-accept-encoding=gzip)
    hello, World
    hello, World
    

    这样在两端就可以看到对应的header

    总结

    通过header的内容可以对调用的流程进行一定的控制,以达到认证等功能。

  • 相关阅读:
    loadrunner -27778 https连接问题
    https调试
    Session Alerts
    Pause Web Sessions
    Customize Web Sessions List
    单例模式:Java单例模式的几种写法及它们的优缺点
    Activity: launchMode 和 Intent.FLAG_ACTIVITY_CLEAR_TOP
    TextView: android:ellipsize="marquee" 跑马灯效果无效的问题
    Socket通信(1):搭建开发环境
    linux: QT安装时出现段错误segmentation fault
  • 原文地址:https://www.cnblogs.com/resentment/p/6818753.html
Copyright © 2011-2022 走看看