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的內容可以對調用的流程進行一定的控制,以達到認證等功能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM