Gin —— 一个Golang微框架
Posted 小米运维
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gin —— 一个Golang微框架相关的知识,希望对你有一定的参考价值。
本篇文章介绍了gin的特点,以及其自定义中间件的原理和方法。
封面图片来自于:pixabay kellepics
Gin 是一个 golang 的 web 框架,
封装优雅,文档完备,已发布 1.2 版本。
具有以下特点:
快,基于 radix tree 路由,内存占用少,无反射;
自定义中间件,易于扩展;
分组路由,更好的组织路由结构;
参数绑定,解析和验证请求数据,可自定义验证方法;
错误管理,提供收集 http 请求过程中所有错误的便捷方式;
内置多种格式渲染。
巧用中间件
支持自定义中间件是当时选择 gin 开发服务的主要原因之一。gin 中间件分为全局中间件、群组中间件和单路由中间件三种。
func main() {
router := gin.New()
//全局中间件
router.Use(GlobalMiddleware())
//群组中间件
api := router.Group("/v1/api", GroupMiddleware())
//单路由中间件
api.GET("/health", SingleMiddleware(), func(ctx *gin.Context) {
ctx.String(http.StatusOK, "ok")
})
router.Run(":8080")
}
完成路由设置后,每个注册的路由规则都会绑定一个 middleware chain,其中最后一个中间件即为业务处理逻辑。接收到的 http 请求,匹配到相应的路由规则后会递归执行 middleware chain,如果中间件 abort,将不会执行后续中间件。
下面简单介绍几种巧用中间件的方法
使用中间件可以在业务逻辑的前后做很多定制处理。
func RequestMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
fmt.Println("before request")
ctx.Next()
fmt.Println("after request")
}
}
通过自定义中间件,可以捕获 http 请求中的异常并恢复,保证服务始终可用。此外,利用自定义错误类型,在处理 http 请求过程中能任意抛出错误,通过中间件的统一捕获,进而简化程序并规范返回结果。
type StatusError struct {
StatusCode int
Msg string}
func (se *StatusError) Error() string {
return fmt.Sprintf("status_code:%d, msg:%s", se.StatusCode, se.Msg)
}
func BadRequestStatusError(msg ...string) StatusError {
status_err := StatusError{
StatusCode: http.StatusBadRequest,
Msg: "bad request",
}
if len(msg) > 0 {
status_err.Msg = msg[0]
}
return status_err
}
func abortWithStatusMsg(ctx *gin.Context, status int, msg string) {
ctx.String(status, msg)
ctx.Abort()
}
func RecoveryMiddleware(out io.Writer) gin.HandlerFunc {
logger := log.New(out, "\n\n\x1b[31m", log.LstdFlags)
return func(ctx *gin.Context) {
defer func() {
if err := recover(); err != nil {
if e, ok := err.(StatusError); ok {
//自定义错误,业务逻辑故意抛出的,返回统一格式数据
abortWithStatusMsg(ctx, e.StatusCode, e.Msg)
return
}
//打印堆栈
stack := make([]byte, 1024*8)
stack = stack[:runtime.Stack(stack, false)]
httprequest, _ := httputil.DumpRequest(ctx.Request, false)
logger.Printf("[Recovery] panic recovered:\n%s\n%s\n%s", string(httprequest), err, stack)
//异常报警
//report to sentry
//返回统一格式数据
abortWithStatusMsg(ctx, http.StatusInternalServerError, "Server error, please contact admin!")
}
}()
ctx.Next()
}
}
func main() {
router := gin.New()
var DefaultWriter io.Writer = os.Stdout
router.Use(RecoveryMiddleware(DefaultWriter))
router.GET("/", func(ctx *gin.Context) {
panic(BadRequestStatusError("this is a test"))
})
router.Run(":8080")
}
通过多个中间件实现不同的登录鉴权方式,并绑定到相应的路由分组,可以很方便的实现同一系统不同路由使用不同鉴权。
func main() {
router := gin.Default()
v1 := router.Group("/v1", V1AuthMiddleware())
v2 := router.Group("/v2", V2AuthMiddleware())
router.Run(":8080")
}
在使用中间件的过程中还需注意以下两点:
注册中间件之前设置的路由,将不受注册中间件的影响。
中间件 abort 时,需立即 return,才不会执行本中间件后续的代码。
其他Point
1、gin 提供了两种 model binding 方式以验证请求的数据,分别是 Must Bind 和 Should Bind。如果验证出错,Must Bind 会返回错误并且
ctx.AbortWithError(400,err).SetType(ErrorTypeBind),Content-Type会被设置成text/plain; charset=utf-8;而 Should Bind 只会返回错误,开发者需自行处理。
2、利用自定义参数验证方法,抽象出常用的验证方式,便于代码复用。
3、利用gin.Context.Errors可以收集 http 请求过程中所有错误,统一处理。
4、在 debug 模式下,请求会实时加载模板便于开发调试;而 release 模式会直接从内存中获取模板以提升服务性能。
5、可以使用 go-swagger 生成 API 自动化文档。
总结
如果你也喜欢自定义中间件,想利用优秀的开源模块堆积木式地搭建自己的 http 服务,gin 会是一个不错的选择。
长按指纹,关注传说中的小米运维
以上是关于Gin —— 一个Golang微框架的主要内容,如果未能解决你的问题,请参考以下文章