原项目:https://github.com/cloudwego/hertz
创建一个用户的微服务用来进行添加和查询用户
Kitex 安装
Kitex 目前对 Windows 的支持并不完善,建议使用虚拟机或 WSL2 进行测试。
这里我采用Ubuntu系统,来自动生成代码然后将生成代码同步到window本地的goland开发!
要开始 Kitex 开发,首先需要安装 Kitex 代码生成工具, go install
命令可被用于安装 Go 二进制工具(在此之前,请务必检查已正确设置 GOPATH
环境变量,并将 $GOPATH/bin
添加到 PATH
环境变量中)
安装依赖
go install github.com/cloudwego/kitex@latest
go install github.com/cloudwego/thriftgo@latest
go mod edit -replace=github.com/apache/thrift=github.com/apache/[email protected]
docker 安装 相关环境
安装文件 docker-compose.yaml
启动命令 docker-compose up -d
namespace go demouser
enum ErrCode {
SuccessCode = 0
ServiceErrCode = 10001
ParamErrCode = 10002
UserAlreadyExistErrCode = 10003
AuthorizationFailedErrCode = 10004
}
struct BaseResp {
1: i64 status_code
2: string status_message
3: i64 service_time
}
struct User {
1: i64 user_id
2: string username
3: string avatar
}
struct CreateUserRequest {
// length of Message should be greater than or equal to 1
1: string username (vt.min_size = "1")
2: string password (vt.min_size = "1")
}
struct CreateUserResponse {
1: BaseResp base_resp
}
struct MGetUserRequest {
1: list<i64> user_ids (vt.min_size = "1")
}
struct MGetUserResponse {
1: list<User> users
2: BaseResp base_resp
}
struct CheckUserRequest {
1: string username (vt.min_size = "1")
2: string password (vt.min_size = "1")
}
struct CheckUserResponse {
1: i64 user_id
2: BaseResp base_resp
}
service UserService {
CreateUserResponse CreateUser(1: CreateUserRequest req)
MGetUserResponse MGetUser(1: MGetUserRequest req)
CheckUserResponse CheckUser(1: CheckUserRequest req)
}
官网
有了 IDL (可以理解为接口)以后我们便可以通过 kitex 工具生成项目代码了,执行如下命令:
$ kitex -module example -service example echo.thrift
上述命令中,-module 表示生成的该项目的 go module 名,-service 表明我们要生成一个服务端项目,后面紧跟的 example 为该服务的名字。最后一个参数则为该服务的 IDL 文件。
生成文件说明
build.sh : 构建脚本,将代码变成一个可执行的二进制文件
kitex_gen : IDL内容相关的生成代码,主要是基础的Server/Client代码,kitex的编解码的优化会在里面,这里是生成的主要代码
main.go : 程序入口
handler.go : 用户在该文件里实现IDL service 定义的方法 可以理解为api层
上面的代码生成是在Linux中的,goland中使用deployment来同步到window中goland下,然后window输入
go mod tidy
来同步包
package main
import (
"context"
"log"
demouser "myuser/kitex_gen/demouser"
"time"
)
// UserServiceImpl implements the last service interface defined in the IDL.
type UserServiceImpl struct{}
// CreateUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) CreateUser(ctx context.Context, req *demouser.CreateUserRequest) (resp *demouser.CreateUserResponse, err error) {
log.Println("姓名" + req.Username + "密码" + req.Password)
resp = new(demouser.CreateUserResponse)
resp.BaseResp = &demouser.BaseResp{StatusCode: 200, StatusMessage: "ok", ServiceTime: time.Time{}.Unix()}
return resp, nil
}
// MGetUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) MGetUser(ctx context.Context, req *demouser.MGetUserRequest) (resp *demouser.MGetUserResponse, err error) {
resp = new(demouser.MGetUserResponse)
users := make([]*demouser.User, 0)
users = append(users, &demouser.User{1, "test", "test"})
resp.Users = users
resp.BaseResp = &demouser.BaseResp{StatusCode: 200, StatusMessage: "ok", ServiceTime: time.Time{}.Unix()}
return resp, nil
}
// CheckUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) CheckUser(ctx context.Context, req *demouser.CheckUserRequest) (resp *demouser.CheckUserResponse, err error) {
resp = new(demouser.CheckUserResponse)
resp.UserId = 1
resp.BaseResp = &demouser.BaseResp{StatusCode: 200, StatusMessage: "ok", ServiceTime: time.Time{}.Unix()}
return resp, nil
}
package main
import (
"log"
"myuser/kitex_gen/demouser/userservice"
)
func main() {
//服务端的地址 [::]:8888,注意要和demouser下的service中名字保持一致,这里userservice
svr := userservice.NewServer(new(UserServiceImpl))
err := svr.Run()
if err != nil {
log.Println(err.Error())
}
}
没有报错说明一起正常,下面进行客户端的编写
运行 sh build.sh
以进行编译,编译结果会被生成至 output
目录.
最后,运行 sh output/bootstrap.sh
以启动服务。服务会在默认的 8888 端口上开始运行。要想修改运行端口,可打开 main.go
,为 NewServer
函数指定配置参数:
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999")
svr := api.NewServer(new(EchoImpl), server.WithServiceAddr(addr))
package main
import (
"context"
"github.com/cloudwego/kitex/client"
"log"
"myuser/kitex_gen/demouser"
"myuser/kitex_gen/demouser/userservice"
"time"
)
func main() {
//第一个是服务名字,第二个是指定服务端的地址
client, err := userservice.NewClient("userservice", client.WithHostPorts("0.0.0.0:8888"))
if err != nil {
log.Fatal(err)
}
for {
//通过client进行调用
resp, err := client.CreateUser(context.Background(), &demouser.CreateUserRequest{Username: "wpc", Password: "123456"})
//resp, err := client.CheckUser(context.Background(), &demouser.CheckUserRequest{Username: "wpc", Password: "123456"})
//resp, err := client.MGetUser(context.Background(), &demouser.MGetUserRequest{UserIds: []int64{1, 2}})
if err != nil {
log.Fatal(err)
return
}
log.Println(resp)
time.Sleep(time.Second)
}
}
服务端
package main
import (
"github.com/cloudwego/kitex/pkg/rpcinfo"
"github.com/cloudwego/kitex/server"
etcd "github.com/kitex-contrib/registry-etcd"
"log"
"myuser/kitex_gen/demouser/userservice"
)
func main() {
//服务端的地址 [::]:8888,注意要和demouser下的service中名字保持一致,这里userservice
// 填写对应的ip地址和端口
r, err := etcd.NewEtcdRegistry([]string{"192.168.1.18:2379"}) // r不应重复使用。
if err != nil {
log.Fatal(err)
}
svr := userservice.NewServer(new(UserServiceImpl),
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "userservice"}),
server.WithRegistry(r))
err = svr.Run()
if err != nil {
log.Println(err.Error())
}
}
客户端
NewClient() 后面的第一个参数要和前面的ServiceName保持一致userservice
package main
import (
"context"
"github.com/cloudwego/kitex/client"
etcd "github.com/kitex-contrib/registry-etcd"
"log"
"myuser/kitex_gen/demouser"
"myuser/kitex_gen/demouser/userservice"
"time"
)
func main() {
//第一个是服务名字,第二个是指定服务端的地址
r, err := etcd.NewEtcdResolver([]string{"192.168.1.18:2379"}) // r不应重复使用。
if err != nil {
log.Fatal(err)
}
client, err := userservice.NewClient("userservice", client.WithResolver(r))
....
}
https://gitee.com/wangpengchengalex/go-easynote/tree/master/demo
使用 gorm-gen 来快速crud 官网
当然也可以是SQL创建
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Username string `json:"username"`
Avatar string `json:"avatar"` //password懒得改了
}
func main() {
dsn := "gorm:gorm@tcp(192.168.1.18:3306)/gorm?charset=utf8&parseTime=True&loc=Local"
println(dsn)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
// 迁移 schema
db.AutoMigrate(&User{})
}
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gen"
"gorm.io/gorm"
)
func main() {
// 连接数据库
db, err := gorm.Open(mysql.Open("gorm:gorm@tcp(192.168.1.18:3306)/gorm?charset=utf8&parseTime=True&loc=Local"))
if err != nil {
panic(fmt.Errorf("cannot establish db connection: %w", err))
}
g := gen.NewGenerator(gen.Config{
OutPath: "D:\\goCode\\myuser\\gorm-gen\\query",
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
})
g.UseDB(db)
// Generate basic type-safe DAO API
g.ApplyBasic(g.GenerateAllTable()...)
g.Execute()
}
package main
import (
"context"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
"myuser/gorm-gen/model"
"myuser/gorm-gen/query"
)
func main() {
// 连接数据库
db, err := gorm.Open(mysql.Open("gorm:gorm@tcp(192.168.1.18:3306)/gorm?charset=utf8&parseTime=True&loc=Local"))
if err != nil {
panic(fmt.Errorf("cannot establish db connection: %w", err))
}
query.SetDefault(db)
// 增加数据
u := query.User
ctx := context.Background()
users := []*model.User{{Username: "test1", Avatar: "test1"}, {Username: "test2", Avatar: "test2"}}
u.WithContext(ctx).Create(users...)
// 查询数据 https://gorm.io/gen/query.html
seach1, _ := u.WithContext(ctx).Where(u.ID.Eq(1)).First()
log.Println("通过id查询", seach1)
// 更新数据 https://blog.csdn.net/Jeffid/article/details/126898000
u.WithContext(ctx).Where(u.Username.Eq("test2")).Update(u.Username, "wpc")
seach2, _ := u.WithContext(ctx).Where(u.Username.Eq("wpc")).First()
log.Println("更新后的查询", seach2)
}
规定 : 将crud的数据访问对象都放入dal文件中,下面主要三个目录 1、db 接下来定义的数据库操作 2、model
3、query (2,3都由gorm-gen生成)
1、init.go
package db
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"myuser/demo/dal/query"
)
var Q *query.Query
func Init() {
var err error
db, err := gorm.Open(mysql.Open("gorm:gorm@tcp(192.168.1.18:3306)/gorm?charset=utf8&parseTime=True&loc=Local"))
if err != nil {
panic(fmt.Errorf("cannot establish db connection: %w", err))
}
query.SetDefault(db)
Q = query.Q
if err != nil {
panic(err)
}
}
2、user.go
package db
import (
"context"
"myuser/demo/dal/model"
)
// MGetUsers multiple get list of user info
func MGetUsers(ctx context.Context, userIDs []int64) ([]*model.User, error) {
return Q.WithContext(ctx).User.Where(Q.User.ID.In(userIDs...)).Find()
}
// CreateUser create user info
func CreateUser(ctx context.Context, users []*model.User) error {
return Q.WithContext(ctx).User.Create(users...)
}
// QueryUser query list of user info
func QueryUser(ctx context.Context, userName string) ([]*model.User, error) {
return Q.WithContext(ctx).User.Where(Q.User.Username.Eq(userName)).Find()
}
3、user_test.go
package db
import (
"context"
"log"
"myuser/demo/dal/model"
"testing"
)
func TestCreateUser(t *testing.T) {
Init()
users := make([]*model.User, 0)
users = append(users, &model.User{Username: "wpctest", Avatar: "123187"})
CreateUser(context.Background(), users)
}
func TestQueryUser(t *testing.T) {
Init()
user, err := QueryUser(context.Background(), "wpctest")
if err != nil {
log.Fatal(err)
}
log.Println(user[0])
}
func TestMGetUsers(t *testing.T) {
Init()
users, err := MGetUsers(context.Background(), []int64{7, 9, 10})
if err != nil {
log.Fatal(err)
}
for _, user := range users {
log.Println(user)
}
}
相关代码地址
建一个目录service
,里面是具体的实现方法,handler.go充当api层
来获取参数和返回数据对象,具体的数据处理由service中的一个一个方法来处理
package errno
import (
"errors"
"fmt"
"myuser/demo/kitex_gen/demouser"
)
type ErrNo struct {
ErrCode int64
ErrMsg string
}
func (e ErrNo) Error() string {
return fmt.Sprintf("err_code=%d, err_msg=%s", e.ErrCode, e.ErrMsg)
}
func NewErrNo(code int64, msg string) ErrNo {
return ErrNo{
ErrCode: code,
ErrMsg: msg,
}
}
func (e ErrNo) WithMessage(msg string) ErrNo {
e.ErrMsg = msg
return e
}
var (
Success = NewErrNo(int64(demouser.ErrCode_SuccessCode), "Success")
ServiceErr = NewErrNo(int64(demouser.ErrCode_ServiceErrCode), "Service is unable to start successfully")
ParamErr = NewErrNo(int64(demouser.ErrCode_ParamErrCode), "Wrong Parameter has been given")
UserAlreadyExistErr = NewErrNo(int64(demouser.ErrCode_UserAlreadyExistErrCode), "User already exists")
AuthorizationFailedErr = NewErrNo(int64(demouser.ErrCode_AuthorizationFailedErrCode), "Authorization failed")
)
// ConvertErr convert error to Errno
func ConvertErr(err error) ErrNo {
Err := ErrNo{}
if errors.As(err, &Err) {
return Err
}
s := ServiceErr
s.ErrMsg = err.Error()
return s
}
package service
import (
"context"
"crypto/md5"
"fmt"
"io"
"myuser/demo/dal/db"
"myuser/demo/dal/model"
errno "myuser/demo/error"
"myuser/demo/kitex_gen/demouser"
)
type CreateUserService struct {
ctx context.Context
}
// NewCreateUserService new CreateUserService
func NewCreateUserService(ctx context.Context) *CreateUserService {
return &CreateUserService{ctx: ctx}
}
func (s *CreateUserService) CreateUser(req *demouser.CreateUserRequest) error {
users, err := db.QueryUser(s.ctx, req.Username)
if err != nil {
return err
}
if len(users) != 0 {
return errno.UserAlreadyExistErr
}
//生成md5
h := md5.New()
if _, err = io.WriteString(h, req.Password); err != nil {
return err
}
password := fmt.Sprintf("%x", h.Sum(nil))
return db.CreateUser(s.ctx, []*model.User{{Username: req.Username, Avatar: password}})
}
package pack
import (
"github.com/cloudwego/biz-demo/easy_note/cmd/user/dal/db"
"github.com/cloudwego/biz-demo/easy_note/kitex_gen/demouser"
)
// User pack user info
func User(u *db.User) *demouser.User {
if u == nil {
return nil
}
return &demouser.User{UserId: int64(u.ID), Username: u.Username, Avatar: ""}
}
// Users pack list of user info
func Users(us []*db.User) []*demouser.User {
users := make([]*demouser.User, 0)
for _, u := range us {
if temp := User(u); temp != nil {
users = append(users, temp)
}
}
return users
}
之前用的是模拟数据这里就是真实的查询数据库
package main
import (
"context"
errno "myuser/demo/error"
"myuser/demo/pack"
"myuser/demo/service"
"myuser/kitex_gen/demouser"
)
// UserServiceImpl implements the last service interface defined in the IDL.
type UserServiceImpl struct{}
// CreateUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) CreateUser(ctx context.Context, req *demouser.CreateUserRequest) (resp *demouser.CreateUserResponse, err error) {
resp = new(demouser.CreateUserResponse)
err = service.NewCreateUserService(ctx).CreateUser(req)
if err != nil {
resp.BaseResp = pack.BuildBaseResp(err)
return resp, nil
}
resp.BaseResp = pack.BuildBaseResp(errno.Success)
return resp, nil
}
// MGetUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) MGetUser(ctx context.Context, req *demouser.MGetUserRequest) (resp *demouser.MGetUserResponse, err error) {
resp = new(demouser.MGetUserResponse)
users, err := service.NewMGetUserService(ctx).MGetUser(req)
if err != nil {
resp.BaseResp = pack.BuildBaseResp(err)
return resp, nil
}
resp.BaseResp = pack.BuildBaseResp(errno.Success)
resp.Users = users
return resp, nil
}
// CheckUser implements the UserServiceImpl interface.
func (s *UserServiceImpl) CheckUser(ctx context.Context, req *demouser.CheckUserRequest) (resp *demouser.CheckUserResponse, err error) {
resp = new(demouser.CheckUserResponse)
uid, err := service.NewCheckUserService(ctx).CheckUser(req)
if err != nil {
resp.BaseResp = pack.BuildBaseResp(err)
return resp, nil
}
resp.UserId = uid
resp.BaseResp = pack.BuildBaseResp(errno.Success)
return resp, nil
}
https://gitee.com/wangpengchengalex/go-easynote/tree/master/demo
很明显上面的是基于微服务的,也不方便调试,需要起一个http框架来使用
官网 https://www.cloudwego.io/docs/hertz/
在目录下创建 idl文件文件夹,写入api.thrift
idl/api.thrift
namespace go demoapi
struct BaseResp {
1: i64 status_code
2: string status_message
3: i64 service_time
}
struct User {
1: i64 user_id
2: string username
3: string avatar
}
struct CreateUserRequest {
1: string username (api.form="username", api.vd="len($) > 0")
2: string password (api.form="password", api.vd="len($) > 0")
}
struct CreateUserResponse {
1: BaseResp base_resp
}
struct CheckUserRequest {
1: string username (api.form="username", api.vd="len($) > 0")
2: string password (api.form="password", api.vd="len($) > 0")
}
struct CheckUserResponse {
1: BaseResp base_resp
}
service ApiService {
CreateUserResponse CreateUser(1: CreateUserRequest req) (api.post="/user/register")
CheckUserResponse CheckUser(1: CheckUserRequest req) (api.post="/user/login")
}
// GOPATH 下执行
hz new -idl idl/api.thrift
// 拉取代码到window中 整理 & 拉取依赖
go mod tidy
这里路由都已经自动生成了
调用 方法和 client完全一致,先注册发现然后调用对应方法
package rpc
import (
"context"
"github.com/cloudwego/kitex/client"
"github.com/kitex-contrib/obs-opentelemetry/tracing"
etcd "github.com/kitex-contrib/registry-etcd"
errno "myuser/demo/error"
"myuser/kitex_gen/demouser"
"myuser/kitex_gen/demouser/userservice"
)
var userClient userservice.Client
func initUser() {
r, err := etcd.NewEtcdResolver([]string{"192.168.1.18:2379"})
if err != nil {
panic(err)
}
c, err := userservice.NewClient(
"userservice",
client.WithResolver(r),
client.WithSuite(tracing.NewClientSuite()),
)
if err != nil {
panic(err)
}
userClient = c
}
// CreateUser create user info
func CreateUser(ctx context.Context, req *demouser.CreateUserRequest) error {
resp, err := userClient.CreateUser(ctx, req)
if err != nil {
return err
}
if resp.BaseResp.StatusCode != 0 {
return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
}
return nil
}
// CheckUser check user info
func CheckUser(ctx context.Context, req *demouser.CheckUserRequest) (int64, error) {
resp, err := userClient.CheckUser(ctx, req)
if err != nil {
return 0, err
}
if resp.BaseResp.StatusCode != 0 {
return 0, errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
}
return resp.UserId, nil
}
修改biz/handler/demoapi的文件
// Code generated by hertz generator.
package demoapi
import (
"context"
"myuser/demo/api/biz/model/demoapi"
"myuser/demo/api/biz/rpc"
errno "myuser/demo/error"
"myuser/kitex_gen/demouser"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
// CreateUser .
// @router /user/register [POST]
func CreateUser(ctx context.Context, c *app.RequestContext) {
var err error
var req demoapi.CreateUserRequest
err = c.BindAndValidate(&req)
if err != nil {
c.String(consts.StatusBadRequest, err.Error())
return
}
//替换掉代码生成的
//resp := new(demoapi.CreateUserResponse)
err = rpc.CreateUser(context.Background(), &demouser.CreateUserRequest{
Username: req.Username,
Password: req.Password,
})
if err != nil {
SendResponse(c, errno.ConvertErr(err), nil)
return
}
//c.JSON(consts.StatusOK, resp)
//自定义json
SendResponse(c, errno.Success, nil)
}
// CheckUser .
// @router /user/login [POST]
func CheckUser(ctx context.Context, c *app.RequestContext) {
var err error
var req demoapi.CheckUserRequest
err = c.BindAndValidate(&req)
if err != nil {
c.String(consts.StatusBadRequest, err.Error())
return
}
//resp := new(demoapi.CheckUserResponse)
//
//c.JSON(consts.StatusOK, resp)
id, err := rpc.CheckUser(context.Background(), &demouser.CheckUserRequest{
Username: req.Username,
Password: req.Password,
})
if err != nil && id == 0 {
SendResponse(c, errno.ConvertErr(err), nil)
return
}
//c.JSON(consts.StatusOK, resp)
//自定义json
SendResponse(c, errno.Success, nil)
}
package demoapi
import (
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/protocol/consts"
errno "myuser/demo/error"
)
type Response struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
// SendResponse pack response
func SendResponse(c *app.RequestContext, err error, data interface{}) {
Err := errno.ConvertErr(err)
c.JSON(consts.StatusOK, Response{
Code: Err.ErrCode,
Message: Err.ErrMsg,
Data: data,
})
}
https://gitee.com/wangpengchengalex/go-easynote/tree/master/demo/api
在 biz下新建一个mw目录然后复制下面的代码,主要改Authenticator
中调用rpc即可
1、自定义key和identitykey
2、这三处保持一致
3、调用rpc方法
package mw
import (
"context"
"net/http"
"time"
"github.com/cloudwego/biz-demo/easy_note/cmd/api/biz/model/demoapi"
"github.com/cloudwego/biz-demo/easy_note/cmd/api/biz/rpc"
"github.com/cloudwego/biz-demo/easy_note/kitex_gen/demouser"
"github.com/cloudwego/biz-demo/easy_note/pkg/consts"
"github.com/cloudwego/biz-demo/easy_note/pkg/errno"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/jwt"
)
var JwtMiddleware *jwt.HertzJWTMiddleware
func InitJWT() {
JwtMiddleware, _ = jwt.New(&jwt.HertzJWTMiddleware{
Key: []byte(consts.SecretKey),
TokenLookup: "header: Authorization, query: token, cookie: jwt",
TokenHeadName: "Bearer",
TimeFunc: time.Now,
Timeout: time.Hour,
MaxRefresh: time.Hour,
IdentityKey: consts.IdentityKey,
IdentityHandler: func(ctx context.Context, c *app.RequestContext) interface{} {
claims := jwt.ExtractClaims(ctx, c)
return &demoapi.User{
UserID: int64(claims[consts.IdentityKey].(float64)),
}
},
PayloadFunc: func(data interface{}) jwt.MapClaims {
if v, ok := data.(int64); ok {
return jwt.MapClaims{
consts.IdentityKey: v,
}
}
return jwt.MapClaims{}
},
Authenticator: func(ctx context.Context, c *app.RequestContext) (interface{}, error) {
var err error
var req demoapi.CheckUserRequest
if err = c.BindAndValidate(&req); err != nil {
return "", jwt.ErrMissingLoginValues
}
if len(req.Username) == 0 || len(req.Password) == 0 {
return "", jwt.ErrMissingLoginValues
}
//修改这里
return rpc.CheckUser(context.Background(), &demouser.CheckUserRequest{
Username: req.Username,
Password: req.Password,
})
},
LoginResponse: func(ctx context.Context, c *app.RequestContext, code int, token string, expire time.Time) {
c.JSON(http.StatusOK, utils.H{
"code": errno.Success.ErrCode,
"token": token,
"expire": expire.Format(time.RFC3339),
})
},
Unauthorized: func(ctx context.Context, c *app.RequestContext, code int, message string) {
c.JSON(http.StatusOK, utils.H{
"code": errno.AuthorizationFailedErr.ErrCode,
"message": message,
})
},
HTTPStatusMessageFunc: func(e error, ctx context.Context, c *app.RequestContext) string {
switch t := e.(type) {
case errno.ErrNo:
return t.ErrMsg
default:
return t.Error()
}
},
})
}
// CheckUser .
// @router /user/login [POST]
func CheckUser(ctx context.Context, c *app.RequestContext) {
mw.JwtMiddleware.LoginHandler(ctx, c)
}
func Init() {
rpc.Init()
mw.InitJWT()
}
func main() {
Init()
h := server.New(
server.WithHostPorts(":8080"),
server.WithHandleMethodNotAllowed(true), // coordinate with NoMethod
)
register(h)
h.Spin()
}
https://blog.csdn.net/wzb_wzt/article/details/115730178
https://www.cloudwego.io/zh/docs/hertz/tutorials/basic-feature/middleware/jwt/#payloadfunc
项目中在api层调用带有jwt的user
...
v, _ := c.Get(consts.IdentityKey) //通过Get 来获取 IdentityHandler 中保存的上下文信息 UserID
notes, total, err := rpc.QueryNotes(context.Background(), &demonote.QueryNoteRequest{
UserId: v.(*demoapi.User).UserID, //
SearchKey: req.SearchKey,
Offset: req.Offset,
Limit: req.Limit,
})
...
调用是需要加上Authorization的头信息
curl --location --request GET '127.0.0.1:8080/v2/note/query?offset=0&limit=20&search_key=test' \
--header 'Authorization: Bearer $token'