在spring cloud里面我们服务之间调用主要使用open-feign来实现的,在这种场景里面会涉及到比如服务之间相互调用,可以通过header头传一些固定值,方便进行数据的采集或者验证。在go-kratos里面其实也是可以做到的,go-kratos里面的实现主要是通过中间件的形式来实现。下面我们使用前面的项目来演示一下。
user-center项目改造
前面我们使用user-center项目里面的login接口调用orders-center服务,那么user-center项目可以看做是客户端,,orders-center服务看做是服务端。所以这里我们首先对user-center项目进行改造。
1、改造client
客户端需要进行传值的话,那么需要在创建客户端的时候注册客户端的中间件。
#在引入的地方添加中间件 import ( mmd "github.com/go-kratos/kratos/v2/middleware/metadata" ) #创建连接的时候,添加中间件为客户端 httpConn, err := http.NewClient( context.Background(), http.WithEndpoint("discovery:///orders-center.http"), http.WithDiscovery(acc.data.nrg), http.WithTimeout(time.Second*2), http.WithMiddleware( mmd.Client(), recovery.Recovery()), )
这里注册这一步非常重要,这是代表当前client需要使用到metadata中间件,启动header头传值。
2、添加传值
接着只需要把当前传值的信息,使用ctx包装起来即可:
clientContext := metadata.AppendToClientContext(ctx, "x-md-global-token", "123456-grpc") rsp, err := client.SayHello(clientContext, &helloword.HelloRequest{ 。。。。。 }
这里关于传值的说明如下:
1、传值的时候是通过上下文的包装来实现的。 2、传值使用append,这里的参数需要把当前方法获取到的ctx传递进来。 3、包装之后生成的是新的context。 4、调用远程服务方法的时候,需要使用新的context。 5、http或者grpc都是使用这种方式进行传值。 6、传值的时候key格式必须要以:x-md-global-xxx或者x-md-local-xxx这两种格式为准,不允许使用其他的,使用其他的会导致服务端获取不到想要传递的值。
到此我们的客户端就改造完了。
orders-center项目改造
上面的角色里面orders-center作为被调用方,也就是服务方,这里主要是两步骤:
1、注册中间件 2、获取值
下面我们演示下
1、改造http和grpc server
在kratos项目里面,启动http server和grpc server主要是通过internal/server/http.go和internal/server/grpc.go这两个文件来实现的,所以这里我们要改造这两个文件,首先改造http.go文件:
#引入metadata import( mmd "github.com/go-kratos/kratos/v2/middleware/metadata" ) #添加server中间件 var opts = []http.ServerOption{ http.Middleware( mmd.Server(), recovery.Recovery(), ), }
接着改造grpc.go文件:
#引入metadata import( mmd "github.com/go-kratos/kratos/v2/middleware/metadata" ) #添加server中间件 var opts = []grpc.ServerOption{ grpc.Middleware( mmd.Server(), recovery.Recovery(), ), }
到此我们服务端的server注册就完成了。
备注:
1、这里注册的时候记得是直接在ServerOption里面添加中间件的注册。 2、这里注册的是mmd.Server(),是服务端,不是客户端,千万别写错了。
2、获取值
接下来我们在对应的方法service里面通过context获取即可,比如这里orders-server被调用的方法是hello word,然后他的实现是在internal/service/greeter.go文件的SayHello方法,这里直接使用官方的代码示例来实现获取值即可:
if md, ok := metadata.FromServerContext(ctx); ok { token := md.Get("x-md-global-token") fmt.Println("获取到从下游请求头的token值是:", token) }
备注:
1、这里获取值的时候,也是从metadata里面获取到的 2、获取值的话,需要从context中获取。这里不涉及到新的context。
启动测试
最后我们把项目启动起来,测试一下
可以看到从服务端获取到了客户端在header头里面传递的值。最后按照惯例,附上本案例的源码,登录后即可下载。
发表评论