如何在gRPC C++客户端修改方法名?ClientInterceptor无法实现
在gRPC C++客户端修改方法名的实现方案
由于gRPC的ClientInterceptor无法修改已创建Call的方法名(方法名在Call初始化阶段就已确定,拦截器仅能修改元数据、消息等后续内容),可以通过以下两种方案实现需求:
方案一:自定义Channel拦截修改(推荐,对上层透明)
通过实现自定义Channel类,在Call创建的入口处修改方法名,上层Stub调用无需修改代码。
步骤1:实现自定义Channel
继承grpc::Channel,重写CreateCall方法,在其中修改方法名并委托给原始Channel:
#include <grpcpp/grpcpp.h> #include <memory> #include <string> class CustomPathChannel : public grpc::Channel { public: explicit CustomPathChannel(std::shared_ptr<grpc::Channel> original_channel) : original_channel_(std::move(original_channel)) {} grpc::ClientCall* CreateCall(grpc::ClientContext* context, const grpc::MethodDescriptor* method, grpc::CompletionQueue* cq, bool start_call) override { // 拼接自定义路径前缀与原方法名 std::string new_full_method = "/your/custom/base/path/" + method->name(); // 基于原MethodDescriptor构建新的实例(MethodDescriptor不可修改) auto new_method = grpc::MethodDescriptor::Builder(method) .SetFullMethodName(new_full_method) .Build(); // 调用原始Channel的CreateCall,传入修改后的MethodDescriptor return original_channel_->CreateCall(context, new_method.get(), cq, start_call); } // 其余纯虚方法直接委托给原始Channel grpc::CompletionQueue* DefaultCompletionQueue() override { return original_channel_->DefaultCompletionQueue(); } void PerformOpsOnCall(grpc::CallOpSetInterface* ops, grpc::ClientCall* call) override { original_channel_->PerformOpsOnCall(ops, call); } void RegisterMethod(const grpc::MethodDescriptor* method) override { original_channel_-> RegisterMethod(method); } private: std::shared_ptr<grpc::Channel> original_channel_; };
步骤2:使用自定义Channel创建Stub
将原始Channel包装为自定义Channel后,传入Stub构造函数:
int main() { // 创建原始Channel auto original_channel = grpc::CreateChannel( "localhost:50051", grpc::InsecureChannelCredentials() ); // 包装为自定义Channel auto custom_channel = std::make_shared<CustomPathChannel>(original_channel); // 使用自定义Channel创建Stub auto stub = MyService::NewStub(custom_channel); // 后续Stub调用会自动使用修改后的方法名,无需额外改动 grpc::ClientContext ctx; MyRequest req; MyResponse resp; auto status = stub->MyMethod(&ctx, req, &resp); return 0; }
方案二:手动构造修改后的MethodDescriptor(适用于少量方法调用)
如果仅需修改个别方法的调用,可以手动构造新的MethodDescriptor,直接调用Channel的CallMethod接口:
grpc::ClientContext context; MyRequest request; MyResponse response; // 获取原方法的MethodDescriptor const auto* original_method = MyService::GetMethodDescriptorForMethod(MyService::METHOD_MY_METHOD); // 构造修改后的全方法名 std::string new_full_method = "/custom/path/" + original_method->name(); auto new_method = grpc::MethodDescriptor::Builder(original_method) .SetFullMethodName(new_full_method) .Build(); // 直接通过Channel调用修改后的方法 grpc::Status status = stub_->channel()->CallMethod( new_method.get(), &context, request, &response );
注意事项
MethodDescriptor是不可变对象,必须通过Builder创建新实例来修改方法名;- 自定义Channel方案对上层业务代码完全透明,适合全局修改方法名的场景;
- 手动构造方案需要逐个处理方法调用,适合局部修改的场景。
内容的提问来源于stack exchange,提问作者haiyubbt
相关产品推荐
相关产品推荐

