在一次rpc请求过程中我们可能不仅仅要使用req里的数据,可能也需要在metadata中放入一些通用数据,比如token、客户端上报的经纬度等信息

一、Java语言实现

1、客户端发送metedata数据

grpc-java采用拦截器的方式发送metedata

public class PayClientInterceptor implements ClientInterceptor {
    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel channel) {

        return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(method, callOptions)) {
            @Override
            public void start(Listener<RespT> responseListener, Metadata headers) {
                headers.put(Metadata.Key.of("token", ASCII_STRING_MARSHALLER), UUID.randomUUID().toString().replaceAll("-",""));
                super.start(responseListener, headers);
            }
        };
    }
}
/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package com.example.payservice;

import io.grpc.*;
import io.grpc.stub.MetadataUtils;

import java.util.UUID;

public class App {

    public static void main(String[] args) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost",10083)
                .usePlaintext()
                .build();
        Metadata metadata = new Metadata();
        metadata.put( Metadata.Key.of("token",Metadata.ASCII_STRING_MARSHALLER), UUID.randomUUID().toString().replaceAll("-",""));
        Channel headChannel = ClientInterceptors.intercept(channel, MetadataUtils.newAttachHeadersInterceptor(metadata));
        PayServiceGrpc.PayServiceBlockingStub payServiceBlockingStub = PayServiceGrpc.newBlockingStub(headChannel);
        PayServicePbEntity.payOrderRes res = payServiceBlockingStub.payOrder(PayServicePbEntity.payOrderReq.newBuilder().setOrderId("order_1")
                .build());
        System.out.println("resCode:"+res.getRetCode()+"\\tresMsg:"+res.getRetMsg());
    }
}

2、服务端接收metedata数据

服务端也需要使用拦截器接收数据

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package com.example.payservice;

import com.example.payservice.impl.PayServiceImpl;
import com.example.payservice.interceptor.MetadataInterceptor;
import io.grpc.Server;
import io.grpc.ServerBuilder;

import java.io.IOException;

public class App {

    public static void main(String[] args) throws IOException, InterruptedException {

        Server server = ServerBuilder.forPort(10083)
                .addService(new PayServiceImpl())
                .intercept(new MetadataInterceptor())
                .build();

        server.start();
        server.awaitTermination();
    }
}
package com.example.payservice.impl;

import com.example.payservice.PayServiceGrpc;
import com.example.payservice.PayServicePbEntity;
import io.grpc.stub.StreamObserver;

public class PayServiceImpl extends PayServiceGrpc.PayServiceImplBase {

    @Override
    public void payOrder(PayServicePbEntity.payOrderReq request, StreamObserver<PayServicePbEntity.payOrderRes> responseObserver) {

        System.out.println("payOrder,order_Id:"+request.getOrderId());

        responseObserver.onNext(PayServicePbEntity.payOrderRes.newBuilder().setRetCode(0)
        .setRetMsg("支付成功")
        .build());
        responseObserver.onCompleted();
    }
}
package com.example.payservice.interceptor;

import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;

public class MetadataInterceptor implements ServerInterceptor {
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        String token = headers.get(Metadata.Key.of("token", Metadata.ASCII_STRING_MARSHALLER));
        System.out.println("token:"+token);
        return next.startCall(call, headers);
    }
}

二、Go语言实现

相比Java来说,go语言显得更清晰、简洁

1、客户端发送