You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GRPC客户端链式自定义拦截器/DialOptions仅最后一个生效问题排查

gRPC客户端多Unary拦截器仅最后一个生效的解决方法

在配置gRPC客户端时,尝试通过多个grpc.WithUnaryInterceptor添加自定义拦截器,发现只有最后一个拦截器被执行,前面的会被跳过。示例代码如下:

myOpt1 := grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
    print("testInterceptor invoked")
    return invoker(ctx, method, req, reply, cc, opts...)
})
myOpt2 := grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
    print("testInterceptor2 invoked")
    return invoker(ctx, method, req, reply, cc, opts...)
})
opts := []grpc.DialOption{
        grpc.WithTransportCredentials(insecure.NewCredentials()),
        myOpt1, // 被跳过
        myOpt2, // 仅这个生效
}

conn, err := grpc.DialContext(context.Background(), "my-adress:443", opts...) // err is nil
myService := pbAugment.NewMyServiceClient(conn)
myService.MyFunction(context.Background()) // 输出: testInterceptor2 invoked

问题原因

grpc.WithUnaryInterceptor的设计逻辑是替换而非追加拦截器。每调用一次该函数生成的DialOption,都会覆盖之前设置的Unary拦截器。因此当你在DialOption切片中放入多个WithUnaryInterceptor生成的选项时,只有最后一个会生效。

解决方案

使用grpc.WithChainUnaryInterceptor替代多个WithUnaryInterceptor,这个方法支持传入多个Unary拦截器函数,会自动将它们按顺序链式组合,执行时会按传入顺序依次调用每个拦截器。

修改后的代码示例:

// 定义两个拦截器函数
interceptor1 := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
    print("testInterceptor invoked")
    return invoker(ctx, method, req, reply, cc, opts...)
}

interceptor2 := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
    print("testInterceptor2 invoked")
    return invoker(ctx, method, req, reply, cc, opts...)
}

opts := []grpc.DialOption{
        grpc.WithTransportCredentials(insecure.NewCredentials()),
        // 用WithChainUnaryInterceptor组合多个拦截器
        grpc.WithChainUnaryInterceptor(interceptor1, interceptor2),
}

conn, err := grpc.DialContext(context.Background(), "my-adress:443", opts...)
if err != nil {
    // 处理错误
}
myService := pbAugment.NewMyServiceClient(conn)
myService.MyFunction(context.Background()) // 输出: testInterceptor invokedtestInterceptor2 invoked

调用时会先执行interceptor1,再执行interceptor2,最后执行实际的RPC调用。如果需要调整执行顺序,只需调整WithChainUnaryInterceptor中参数的顺序即可。

内容的提问来源于stack exchange,提问作者NotX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:03:30