引入 Redis
在之前的 user 微服务中引入 redis。
1. 修改 user/internal/config/config.go
package configimport ("github.com/zeromicro/go-zero/core/stores/cache""github.com/zeromicro/go-zero/zrpc"
)type Config struct {zrpc.RpcServerConfMysql MysqlConfigCacheRedis cache.CacheConf // redis config -- 加入这一行代码
}type MysqlConfig struct {DataSource string
}
2. 修改 user/etc/user.yaml 文件
加入 redis的配置
CacheRedis:- Host: 127.0.0.1:6379Pass: thinkerType: node
3. 修改 user/database/sqlx.go 文件
修改这里,是为了在查询数据时候,利用redis做缓存。
import ("github.com/zeromicro/go-zero/core/stores/cache""github.com/zeromicro/go-zero/core/stores/sqlc""github.com/zeromicro/go-zero/core/stores/sqlx"
)// we use go-zero sqlxtype DBConn struct {Conn sqlx.SqlConn // mysqlConnCache sqlc.CachedConn // redis
}func Connect(datasource string, conf cache.CacheConf) *DBConn {sqlConn := sqlx.NewMysql(datasource)d := &DBConn{Conn: sqlConn,}if conf != nil {cachedConn := sqlc.NewConn(sqlConn, conf)d.ConnCache = cachedConn}return d
}
4. 修改 /user/internal/svc/servicecontext.go 文件
package svcimport ("user/database""user/internal/config""user/internal/dao""user/internal/repo"
)type ServiceContext struct {Config config.ConfigUserRepo repo.UserRepo
}func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config: c,UserRepo: dao.NewUserDao(database.Connect(c.Mysql.DataSource, c.CacheRedis)), // 增加了 redis的缓冲配置}
}
5. 在 user/internal/repo/user.go 中增加接口
package repoimport ("context""user/internal/model"
)type UserRepo interface {Save(ctx context.Context, user *model.User) errorFindById(ctx context.Context, id int64) (user *model.User, err error) //新增
}
6. 在 user/internal/dao/user.go 中实现接口
func (d *UserDao) FindById(ctx context.Context, id int64) (user *model.User, err error) {user = &model.User{}querySql := fmt.Sprintf("select * from %s where id = ?", user.TableName())userIdKey := fmt.Sprintf("%s%d", cacheUserIdPrefix, id)err = d.ConnCache.QueryRowCtx(ctx, user, userIdKey,func(ctx context.Context, conn sqlx.SqlConn, v any) error {return conn.QueryRowCtx(ctx, v, querySql, id)})return
}
7. 在 user/logic/userlogic.go 中实现 GetUser rpc
func (l *UserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {// todo: add your logic here and delete this lineid, err := strconv.ParseInt(in.Id, 10, 64)if err != nil {return nil, err}u, err := l.svcCtx.UserRepo.FindById(context.Background(), id)if err != nil {return nil, err}return &user.UserResponse{Id: in.GetId(),Name: u.Name,Gender: u.Gender,}, nil
}
User 微服务rpc接口增加缓存完成。
测试
1. 修改 userapi/internal/handler/routes.go 文件
增加如下路由代码
{Method: http.MethodGet,Path: "/user/get/:id",Handler: handler.GetUser,
},
2. 修改 userapi/internal/types/types.go 文件
增加一个 IdRequest 结构体,主要是为了处理上一步中的请求
type IdRequest struct {Id string `json:"name" path:"id"`
}
3. 修改 userapi/internal/handler/userhandler.go 文件,实现GetUser接口
文件中增加如下代码:
func (u *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {var req types.IdRequestif err := httpx.ParsePath(r, &req); err != nil {httpx.ErrorCtx(r.Context(), w, err)return}l := logic.NewUserLogic(r.Context(), u.svcCtx)resp, err := l.GetUser(&req)if err != nil {httpx.ErrorCtx(r.Context(), w, err)} else {httpx.OkJsonCtx(r.Context(), w, resp)}
}
4. 修改 userapi/internal/logic/userapilogic.go 文件
文件中增加 GetUser 方法
func (l *UserLogic) GetUser(t *types.IdRequest) (resp *types.Response, err error) {userResponse, err := l.svcCtx.UserRpc.GetUser(context.Background(), &user.IdRequest{Id: t.Id,})if err != nil {return nil, err}resp = &types.Response{Message: "success",Data: userResponse,}return
}
该方法主要调用了 user微服务的 RPC GetUser接口 服务
5. 启动微服务开始测试
- 启动 user 服务
- 启动 user api 服务
- 测试截图
到此,引入 redis 缓存成功。
go-zero 中的 JWT 使用
jwt 在目前登录、鉴权等场景中引用非常广泛
jwt 是加密的字符串,需要一个密钥,并且可以通过设置过期时间来使 jwt 生成的 token 失效。
由于我们的 userapi 微服务是对外提供接口的,因此,我们在 userapi 中使用 jwt。
1. 修改 userapi/internal/config/config.go 文件
添加 Auth 结构体
package configimport ("github.com/zeromicro/go-zero/rest""github.com/zeromicro/go-zero/zrpc"
)type Config struct {rest.RestConfUserRpc zrpc.RpcClientConfAuth struct {AccessSecret stringAccessExpire int64}
}
2. 修改 userapi/etc/userapi-api.yaml 文件
在文件中,增加如下配置。
Auth:AccessSecret: "sdskewie@129120$%120&*!"AccessExpire: 604800
3. 修改 userapi/internal/handler/routers.go 文件
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {handler := NewUserHandler(serverCtx)server.AddRoutes([]rest.Route{{Method: http.MethodPost,Path: "/Register",Handler: handler.Register,},{Method: http.MethodPost,Path: "/Login",Handler: handler.Login,},},)server.AddRoutes([]rest.Route{{Method: http.MethodGet,Path: "/user/get/:id",Handler: handler.GetUser,},},rest.WithJwt(serverCtx.Config.Auth.AccessSecret), // need jwt)
}
需要 jwt 认证的接口,就需要 rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
这行go代码 。
4. 修改 userapi/internal/handler/userhandler.go 文件 ,实现 Login 接口
在该 文件 中,添加 Login 方法
func (u *UserHandler) Login(w http.ResponseWriter, r *http.Request) {var req types.LoginRequestif err := httpx.ParseJsonBody(r, &req); err != nil {httpx.ErrorCtx(r.Context(), w, err)return}l := logic.NewUserLogic(r.Context(), u.svcCtx)resp, err := l.Login(&req)if err != nil {httpx.ErrorCtx(r.Context(), w, err)} else {httpx.OkJsonCtx(r.Context(), w, resp)}
}
5. 修改 userapi/internal/login/userapilogin.go 文件
在该文件中,添加 login 方法,登录成功后生成 jwt
func (l *UserLogic) getToken(secretKey string, iat, seconds int64, userId int) (string, error) {claims := make(jwt.MapClaims)claims["exp"] = iat + secondsclaims["iat"] = iatclaims["userId"] = userIdtoken := jwt.New(jwt.SigningMethodES256)token.Claims = claimsreturn token.SignedString([]byte(secretKey))
}func (l *UserLogic) Login(t *types.LoginRequest) (string, error) {userId := 100auth := l.svcCtx.Config.Authreturn l.getToken(auth.AccessSecret, time.Now().Unix(), auth.AccessExpire, userId)
}
6. 启动 useapi微服务 测试
- 加入 jwt 后,再次测试 user/get/1接口,返回401
- 先登录,拿到 jwt
- 使用 jwt 访问 user/get/1 接口
jwt 测试成功。
github位置