go-zero中跨服务传递载体信息
go-zero中跨服务传递载体信息
➜ plangz git:(dev) ✗ cat pkg/ctxkey/keys.go
package ctxkey
import "context"
type contextKey string
const (
UserIDKey contextKey = "X-User-ID"
)
func GetUserID(ctx context.Context) int64 {
v := ctx.Value(UserIDKey)
if v == nil {
return 0
}
return v.(int64)
}
➜ plangz git:(dev) ✗
网关 api 服务中的认证中间件 authmiddleware.go:
func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 提取并验证JWT
tokenString := extractToken(r)
if tokenString == "" {
zerror.WriteCodeError(w, 401, "未提供认证令牌")
return
}
// 解析令牌
claims, err := jwtutil.ParseToken(m.secret, tokenString)
if err != nil {
zerror.WriteCodeError(w, 401, "无效的访问令牌")
return
}
// 设置上下文
ctx := context.WithValue(r.Context(), ctxkey.UserIDKey, claims.UserID)
// 关键步骤:将 UserID 注入 gRPC 元数据
ctx = metadata.AppendToOutgoingContext(ctx,
string(ctxkey.UserIDKey), // 元数据键(转为字符串)
fmt.Sprintf("%d", claims.UserID), // 元数据值(转为字符串)
)
next(w, r.WithContext(ctx))
}
}
添加 metadata
拦截器:
➜ plangz git:(dev) ✗ cat apps/user/internal/interceptor/metadata_interceptor.go
package interceptor
import (
"context"
"fmt"
"plangz/pkg/ctxkey"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func MetadataInterceptor(ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp interface{}, err error) {
// 从 gRPC 元数据中提取 UserID
if md, ok := metadata.FromIncomingContext(ctx); ok {
values := md.Get(string(ctxkey.UserIDKey))
if len(values) > 0 {
userIDStr := values[0]
var userID int64
fmt.Sscanf(userIDStr, "%d", &userID)
// 将 UserID 存入当前请求上下文
ctx = context.WithValue(ctx, ctxkey.UserIDKey, userID)
}
}
return handler(ctx, req)
}
➜ plangz git:(dev) ✗
注册拦截器:
func main() {
fmt.Println("=== User Service Started ===")
flag.Parse()
var c config.Config
conf.MustLoad(*configFile, &c)
ctx := svc.NewServiceContext(c)
// 注册拦截器
serverOptions := []grpc.ServerOption{
grpc.UnaryInterceptor(interceptor.MetadataInterceptor),
}
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
user.RegisterUserServer(grpcServer, server.NewUserServer(ctx))
if c.Mode == service.DevMode || c.Mode == service.TestMode {
reflection.Register(grpcServer)
}
})
// 添加拦截器配置
s.AddOptions(serverOptions...)
defer s.Stop()
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
s.Start()
}
网关 api 服务中通过 ctxkey.GetUserID(l.ctx)
获取载体信息:
func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResp, err error) {
// todo: add your logic here and delete this line
userId := ctxkey.GetUserID(l.ctx)
fmt.Println("userId = ", userId)
resp = &types.UserInfoResp{
Name: "plangz",
Phone: "13800138000",
Email: "email@plangz.com",
}
result, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &user.UserInfoReq{})
fmt.Println("result", result)
return
}
user 服务中通过 ctxkey.GetUserID(l.ctx)
获取载体信息:
func (l *UserInfoLogic) UserInfo(in *user.UserInfoReq) (*user.UserInfoResp, error) {
// todo: add your logic here and delete this line
fmt.Println("in user service, userId =", ctxkey.GetUserID(l.ctx))
return &user.UserInfoResp{
Name: "plangz",
Phone: "13800138000",
Email: "email@plangz.com",
}, nil
}