1 启动gin http server
func NewServer(ip string, port int, fs …func(r *gin.Engine)) *GinServer
@param ip string IP地址
@param port int 监听端口
@param fs …func(r *gin.Engine) 处理函数
@return *bzgin.GinServer 结构体,主要用于调用Start()启动服务
// 方式1
server := bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.GET("", func(c *gin.Context) {
c.String(200, "hello")
})
})
server.Start()
// 方式2
server := bzgin.NewServer("127.0.0.1", 8080)
server.GET("", func(c *gin.Context) {
c.String(200, "hello")
})
server.Start()
# curl http://127.0.0.1:8080
hello
2 获取http上下文的数据
func CtxGet[T any](ctx *gin.Context, key string) (T, bool)
@param ctx *gin.Context 传入上下文
@param key string 数据键名
@return T 泛型数据,获得泛型转化后的数据
@return bool 是否获得数据 或 是否转换泛型成功
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.GET("", func(c *gin.Context) {
c.Set("float", 3.1415926)
c.Set("int", 2)
c.Set("string", "hello")
f, ok := bzgin.CtxGet[float64](c, "float")
fmt.Println(f, ok)
i, ok := bzgin.CtxGet[int](c, "int")
fmt.Println(i, ok)
s, ok := bzgin.CtxGet[string](c, "string")
fmt.Println(s, ok)
})
}).Start()
3.1415926 true
2 true
hello true
3 跨域
func Cors(urls …string) gin.HandlerFunc
@param urls 允许跨域的域名,为空则默认使用通配符*
@return gin.HandlerFunc gin中间件类型
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.Use(bzgin.Cors()) // 默认*
r.Use(bzgin.Cors("http://xxx.com")) // Header Origin(来源链接)
}).Start()
4 下载文件流
func FileStream(ctx *gin.Context, file string)
@param ctx *gin.Context gin http上下文
@paam file string 文件
func FileDataStream(ctx *gin.Context, file string) error
@param ctx *gin.Context gin http上下文
@paam file string 文件
@return error 错误信息
// 两种方式结果一样, 依赖gin处理更安全,os处理更少调用性能更好
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.GET("fileStream", func(c *gin.Context) {
bzgin.FileStream(c, "./test.txt") // 依赖gin处理文件流
})
r.GET("fileDataStream", func(c *gin.Context) {
bzgin.FileDataStream(c, "./test.txt") // os处理文件流
})
}).Start()
5 配置默认日志输出文件
func DefaultLog(file string) error
@param file string 文件
@return error 错误信息
bzgin.DefaultLog("./test.log")
bzgin.NewServer("127.0.0.1", 8080).Start()
6 访问日志中间件
func AccessLogHandler(f func(log *ResponseLog)) gin.HandlerFunc
@param f func(log *ResponseLog) 访问日志数据接收方法
@return gin.HandlerFunc gin中间件类型
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.Use(bzgin.AccessLogHandler(func(log *bzgin.ResponseLog) {
fmt.Println(log)
}))
}).Start()
7 捕获http全局错误
func Recover(isPrintStack, isOutStackErr bool, f func(c *gin.Context, err error)) gin.HandlerFunc
@param isPrintStack bool 是否打印堆栈错误
@param isOutStackErr bool 是否向输出函数输出堆栈错误
@param f func(c *gin.Context, err error) 输出函数
@return gin.HandlerFunc gin中间件类型
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.Use(bzgin.Recover(false, false,
func(c *gin.Context, err error) {
c.String(500, err.Error())
},
))
r.GET("", func(c *gin.Context) {
panic("panic")
})
}).Start()
# curl http://127.0.0.1:8080
server internal error
8 http响应
Response数据
type Response struct {
Code intjson:"code"
// 业务状态码,包含:200、400、500
Message stringjson:"message"
// 业务信息
ReasonCode stringjson:"reasonCode"
// 服务状态码,包含 SUCCESS、BAD_REQUEST、SERVER_ERROR
Reason stringjson:"reason"
// 服务信息
Data anyjson:"data"
// 业务数据
}
成功响应
func SuccessResponse(c *gin.Context, data any, message …string)
@param ctx *gin.Context gin http上下文
@param data any 业务数据
@message …string 业务信息,不必要字段
请求错误响应
func BadRequestResponse(c *gin.Context, message string, reason …string)
@param ctx *gin.Context gin http上下文
@message string 业务信息
@reason …string 服务信息,不必要字段
服务错误响应
func ErrorResponse(c *gin.Context, message string, reason …string)
@param ctx *gin.Context gin http上下文
@message string 业务信息
@reason …string 服务信息,不必要字段
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.GET("bad", func(c *gin.Context) {
if c.Query("auth") != "b" {
// 400错误
bzgin.BadRequestResponse(c, "权限验证失败")
return
}
// 200成功
bzgin.SuccessResponse(c, struct{ name string }{name: "breeze"})
})
r.GET("err", func(c *gin.Context) {
// 500错误
bzgin.ErrorResponse(c, "服务异常")
})
}).Start()
9 参数验证
支持Query
、Json
、Header
、Uri
参数验证,提供ValidateQuery
、ValidateJson
、ValidateHeader
、ValidateUri
、ValidateQueryWithFilter
、ValidateJsonWithFilter
、ValidateHeaderWithFilter
、ValidateUriWithFilter
函数
func ValidateQuery[T any](f func(ctx *gin.Context, param *T), errFunc …ValidateErrFunc) func(ctx *gin.Context)
@param f func(ctx *gin.Context, param *T) bzgin的http handle方法
@param errFunc …bzgin.ValidateErrFunc 可自定义处理异常的方法
@return func(ctx *gin.Context) http handle方法
// 错误类型_err,如:required_err:"userId不能为空"
// err,如:err:"userId错误"
// 没有定义错误,如:user的格式需遵守: required
type RequestDto struct {
Name string `form:"name" binding:"required" required_err:"name是必要字段"`
Age int `form:"age" binding:"required" err:"请输入age"`
Desc string `form:"desc" binding:"required"`
}
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.GET("", bzgin.ValidateQuery(func(c *gin.Context, param *RequestDto) {
fmt.Println(param.Name)
}))
r.GET("filter", bzgin.ValidateQueryWithFilter(func(c *gin.Context, param *RequestDto) {
fmt.Println(param.Name)
}))
}).Start()
# curl http://127.0.0.1:8080
{
"code": 400,
"message": "请求参数错误",
"reasonCode": "BAD_REQUEST",
"reason": "Key: 'RequestDto.Name' Error:Field validation for 'Name' failed on the 'required' tag\nKey: 'RequestDto.Age' Error:Field validation for 'Age' failed on the 'required' tag\nKey: 'RequestDto.Desc' Error:Field validation for 'Desc' failed on the 'required' tag",
"data": null
}
# curl http://127.0.0.1:8080/filter
{
"code": 400,
"message": "请求参数错误",
"reasonCode": "BAD_REQUEST",
"reason": "name是必要字段",
"data": null
}
# curl http://127.0.0.1:8080/filter?name=breeze
{
"code": 400,
"message": "请求参数错误",
"reasonCode": "BAD_REQUEST",
"reason": "请输入age",
"data": null
}
# curl http://127.0.0.1:8080/filter?name=breeze&age=18
{
"code": 400,
"message": "请求参数错误",
"reasonCode": "BAD_REQUEST",
"reason": "Desc的格式需遵守: required",
"data": null
}
10 jwt
实例化jwt
func NewJwt[C any, T any](signingKey string) *Jwt[C, T]
@type [C] jwt中保存数据的结构体
@type [T] 支持gin中间件中 根据jwt保存的数据解析后 获得关键信息并存储用户信息的结构体
@param signingKey string 加密密钥
@return *Jwt[C, T] 实例结构体
gin中间件方法
func (j *Jwt[C, T]) Handler(
dataFunc func(claims C, token string) (data T, msg string, err error) , // 解析并存储用户信息
badResponseFuncs …func(c *gin.Context, msg string, err error), // 注册错误响应方法,默认使用 bzgin.BadRequestResponse
) gin.HandlerFunc
@param func(claims C, token string) (data T, msg string, err error)
@param claims [C] jwt存储的数据
@param token string jwt token字符串,方便用于后续到数据库匹配
@return data [T] 用户信息
@return msg string 可用于业务信息
@return err error 错误信息
@return gin.HandlerFunc gin中间件类型
获取用户数据
func (j *Jwt[C, T]) GetJwtData(c *gin.Context) (T, bool)
@param ctx *gin.Context gin http上下文
@return T 用户数据
@return bool 是否获取成功
解析token(有中间件解析的情况下一般用不上)
func (j *Jwt[C, T]) ParseJwtInfo(token string) (C, bool, error)
@param token string 用户token
@return [C] 设置jwt存储的数据
@return error 错误信息
// jwt数据
type MemberClaims struct {
Id uint
}
// 用户数据
type Member struct {
Id uint
Name string
Age int
}
signingKey := "breeze" // 加密密钥
jwt := bzgin.NewJwt[*MemberClaims, *Member](signingKey)
bzgin.NewServer("127.0.0.1", 8080, func(r *gin.Engine) {
r.GET("getToken", func(c *gin.Context) {
token, err := jwt.GenToken(func(claims *bzgin.Claims[*MemberClaims]) *bzgin.Claims[*MemberClaims] {
claims.Data = &MemberClaims{Id: 99} // 切记是直接赋值Data
return claims
}, 10*time.Minute) // token有效期
fmt.Println(token, err)
})
r.Use(jwt.Handler(
// 用户数据写入数据缓存到上下文,此处得到token,从数据库获取后,存入上下文用
func(claims *MemberClaims, token string) (data *Member, msg string, err error) {
return &Member{ Id: 99, Name: "Breeze", Age: 18 }, "", nil
}))
r.GET("getMember", func(c *gin.Context) {
data, ok := jwt.GetJwtData(c) // 从上下文获取用户数据
fmt.Println(data, ok)
})
}).Start()
# curl http://127.0.0.1:8080/getToken
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJEYXRhIjp7IklkIjo5OX0sImV4cCI6MTY5MjQ2NTIyNiwiaWF0IjoxNjkyNDY0NjI2fQ._Zce7vBX2kXmuQKbOHtZY3I_QgFXv0lln5NdKUnORfU <nil>
# curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJEYXRhIjp7IklkIjo5OX0sImV4cCI6MTY5MjQ2NTIyNiwiaWF0IjoxNjkyNDY0NjI2fQ._Zce7vBX2kXmuQKbOHtZY3I_QgFXv0lln5NdKUnORfU" http://127.0.0.1:8080/getMember
&{99 Breeze 18} true