在之前的 user 微服务中引入 redis。
package config
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
zrpc.RpcServerConf
Mysql MysqlConfig
CacheRedis cache.CacheConf // redis config -- 加入这一行代码
}
type MysqlConfig struct {
DataSource string
}
加入 redis的配置
CacheRedis:
- Host: 127.0.0.1:6379
Pass: thinker
Type: node
修改这里,是为了在查询数据时候,利用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 sqlx
type DBConn struct {
Conn sqlx.SqlConn // mysql
ConnCache 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
}
package svc
import (
"user/database"
"user/internal/config"
"user/internal/dao"
"user/internal/repo"
)
type ServiceContext struct {
Config config.Config
UserRepo repo.UserRepo
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRepo: dao.NewUserDao(database.Connect(c.Mysql.DataSource, c.CacheRedis)), // 增加了 redis的缓冲配置
}
}
package repo
import (
"context"
"user/internal/model"
)
type UserRepo interface {
Save(ctx context.Context, user *model.User) error
FindById(ctx context.Context, id int64) (user *model.User, err error) //新增
}
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
}
func (l *UserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
// todo: add your logic here and delete this line
id, 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接口增加缓存完成。
增加如下路由代码
{
Method: http.MethodGet,
Path: "/user/get/:id",
Handler: handler.GetUser,
},
增加一个 IdRequest 结构体,主要是为了处理上一步中的请求
type IdRequest struct {
Id string `json:"name" path:"id"`
}
文件中增加如下代码:
func (u *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
var req types.IdRequest
if 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)
}
}
文件中增加 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接口 服务
jwt 在目前登录、鉴权等场景中引用非常广泛
jwt 是加密的字符串,需要一个密钥,并且可以通过设置过期时间来使 jwt 生成的 token 失效。
由于我们的 userapi 微服务是对外提供接口的,因此,我们在 userapi 中使用 jwt。
添加 Auth 结构体
package config
import (
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
Auth struct {
AccessSecret string
AccessExpire int64
}
}
在文件中,增加如下配置。
Auth:
AccessSecret: "sdskewie@129120$%120&*!"
AccessExpire: 604800
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代码 。
在该 文件 中,添加 Login 方法
func (u *UserHandler) Login(w http.ResponseWriter, r *http.Request) {
var req types.LoginRequest
if 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)
}
}
在该文件中,添加 login 方法,登录成功后生成 jwt
func (l *UserLogic) getToken(secretKey string, iat, seconds int64, userId int) (string, error) {
claims := make(jwt.MapClaims)
claims["exp"] = iat + seconds
claims["iat"] = iat
claims["userId"] = userId
token := jwt.New(jwt.SigningMethodES256)
token.Claims = claims
return token.SignedString([]byte(secretKey))
}
func (l *UserLogic) Login(t *types.LoginRequest) (string, error) {
userId := 100
auth := l.svcCtx.Config.Auth
return l.getToken(auth.AccessSecret, time.Now().Unix(), auth.AccessExpire, userId)
}