GIN 入门手册
Gin 是一个用 Go 编写的 Web 框架。在 Go 项目中使用通常会使用 package:import "github.com/gin-gonic/gin"
。本文主要是帮助大家快速上手,给出 Gin 基本用法的示例,并不涉及底层架构的讲解。
常用的结构和代码
最简单的 Demo
package main
import "github.com/gin-gonic/gin"
func main ( ) {
r := gin.Default ( )
r.GET ( "/ping", func ( c *gin.Context ) {
c.JSON ( 200, gin.H{
"message": "pong",
})
})
r.Run ( ) // 监听并在 0.0.0.0:8080 上启动服务
}
Group 路由组
类似于 Flask 中的 blueprint,用于组织路由地址的层次。router 的底层实现使用的是字典树。
func main ( ) {
router := gin.Default ( )
// 简单的路由组: v1
v1 := router.Group ( "/v1" )
{
v1.GET ( "/login", loginHandler ( )) //url: http://0.0.0.0:8080/v1/login
v1.GET ( "/setting", settingHandler ( )) //url: http://0.0.0.0:8080/v1/setting
}
router.Run ( ":8080" )
}
//定义中间件
func loginHandler ( ) gin.HandlerFunc {
return func ( c *gin.Context ) {
c.JSON ( 200, gin.H{
"message": "successfully login!!",
})
}
}
func settingHandler ( ) gin.HandlerFunc {
return func ( c *gin.Context ) {
c.JSON ( 200, gin.H{
"message": "successfully setting!!",
})
}
}
中间件
中间件是 Gin 中非常重要的一个部分。
中间件的作用
- Web 请求到到达我们定义的 HTTP 请求处理方法之前,拦截请求并进行相应处理 ( 比如: 权限验证,数据过滤等 ) ,这个可以类比为前置拦截器或前置过滤器。
- 在我们处理完成请求并响应客户端时,拦截响应并进行相应的处理 ( 比如: 添加统一响应部头或数据格式等 ) ,这可以类比为后置拦截器或后置过滤器。
中间件实际上就是一个以 gin.Context
为形参的函数。Gin 中有许多内置的中间件:
func BasicAuth ( accounts Accounts ) HandlerFunc
func BasicAuthForRealm ( accounts Accounts, realm string ) HandlerFunc
func Bind ( val interface{} ) HandlerFunc
func ErrorLogger ( ) HandlerFunc
func ErrorLoggerT ( typ ErrorType ) HandlerFunc
func Logger ( ) HandlerFunc
func LoggerWithConfig ( conf LoggerConfig ) HandlerFunc
func LoggerWithFormatter ( f LogFormatter ) HandlerFunc
func LoggerWithWriter ( out io.Writer, notlogged ...string ) HandlerFunc
func Recovery ( ) HandlerFunc
func RecoveryWithWriter ( out io.Writer ) HandlerFunc
func WrapF ( f http.HandlerFunc ) HandlerFunc
func WrapH ( h http.Handler ) HandlerFunc
使用示例:
func main ( ) {
r := gin.Default ( )
r.Use ( gin.BasicAuth ( gin.Accounts{
"admin": "123456",
}) )
r.GET ( "/", func ( c *gin.Context ) {
c.JSON ( 200, "通过验证, 欢迎进入首页" )
})
r.Run ( ":8080" )
}
中间件的自定义
func MyMiddleware ( ) {
return func ( c *gin.Context ) {
//do something
}
}
//使用时
//Default 意味着全局中间件
router = gin.Default ( )
router.Use ( MyMiddleware ( )) //注意 MyMiddleware 有括号
//Group 意味着分组使用
adminGroup := r.Group ( "/admin" )
adminGroup.Use ( gin.BasicAuth ( gin.Accounts{
"admin": "123456"
} ))
adminGroup.GET ( "/index", func ( c *gin.Context ) {
c.JSON ( 200, "后台首页" )
} )
数据传递
当我们在中间件拦截并预先处理好数据之后,要如何将数据传递我们定义的处理请求的 HTTP 方法呢?可以使用 gin.Context
中的 Set ( )
方法。其定义如下:Set ( )
通过一个 key 来存储作何类型的数据,方便下一层处理方法获取。
func MyMiddleware ( c *gin.Context ) {
c.Set ( "mykey",10 )
}
router := gin.New ( )
router.GET ( "test",MyMiddleware,func ( c *gin.Context ) {
c.GetInt ( "mykey" )
} )
对应的方法有:
func ( c *Context ) GetBool ( key string ) ( b bool )
func ( c *Context ) GetDuration ( key string ) ( d time.Duration )
func ( c *Context ) GetFloat64 ( key string ) ( f64 float64 )
func ( c *Context ) GetInt ( key string ) ( i int )
func ( c *Context ) GetInt64 ( key string ) ( i64 int64 )
func ( c *Context ) GetString ( key string ) ( s string )
func ( c *Context ) GetStringMap ( key string ) ( sm map [string] interface{} )
func ( c *Context ) GetStringMapString ( key string ) ( sms map [string] string )
func ( c *Context ) GetStringMapStringSlice ( key string ) ( smss map [string][]string )
func ( c *Context ) GetStringSlice ( key string ) ( ss []string )
func ( c *Context ) GetTime ( key string ) ( t time.Time )
拦截请求与后置拦截
拦截请求
比如我们有些请求需要用户登录或者需要特定权限才能访问,这时候便可以中间件中做过滤拦截,当用户请求不合法时,可以使用下面列出的 gin.Context
的几个方法中断用户请求:
下面三个方法中断请求后,直接返回 200
,但响应的 body 中不会有数据。
func ( c *Context ) Abort ( )
func ( c *Context ) AbortWithError ( code int, err error ) *Error
func ( c *Context ) AbortWithStatus ( code int )
使用 AbortWithStatusJSON ( )
方法,中断用户请求后,则可以返回 json 格式的数据。
func ( c *Context ) AbortWithStatusJSON ( code int, jsonObj interface{} )
后置拦截
前面我们讲的都是到达我们定义的 HTTP 处理方法前进行拦截,其实,如果在中间件中调用 gin.Context
的 Next ( )
方法,则可以请求到达并完成业务处理后,再经过中间件后置拦截处理。
在中间件调用 Next ( )
方法,Next ( )
方法之前的代码会在到达请求方法前执行,Next ( )
方法之后的代码则在请求方法处理后执行。示例如下:
func MyMiddleware ( c *gin.Context ) {
c.Set ( "key",1000 )
c.Next ( )
c.JSON ( http.StatusOK,c.GetInt ( "key" ))
}
router := gin.New ( )
router.GET ( "/test", MyMiddleware, func ( c *gin.Context ) {
k := c.GetInt ( "key" )
c.Set ( "key", k+2000 )
} )
router.Run ( )
运行结果返回值为 3000。
同步响应和异步响应
每次 request 请求 Gin 会开启新的 goroutine 来处理请求。Gin 同时支持请求的同步响应和异步响应。示例如下:
func main ( ) {
// 1.创建路由
// 默认使用了 2 个中间件 Logger ( ) , Recovery ( )
r := gin.Default ( )
// 1.异步
r.GET ( "/long_async", func ( c *gin.Context ) {
// 必须搞一个副本不能直接传递
copyContext := c.Copy ( )
c.JSON ( http.StatusOK, "异步调用返回" )
// 异步处理
go func ( ) {
log.Println ( "开始异步执行: " + copyContext.Request.URL.Path )
time.Sleep ( 8 * time.Second )
log.Println ( "结束异步执行: " + copyContext.Request.URL.Path )
} ( )
})
// 2.同步
r.GET ( "/long_sync", func ( c *gin.Context ) {
log.Println ( "开始同步执行: " + c.Request.URL.Path )
time.Sleep ( 5 * time.Second )
log.Println ( "开始同步执行: " + c.Request.URL.Path )
c.JSON ( http.StatusOK, "同步调用返回" )
})
r.Run ( ":8080" )
}
关于父子 goroutine 之间的关系可参考: 主 goroutine 结束,子 goroutine 也立即结束? 和 Goroutine 理解 两篇博客。
Docker 打包部署
本文参考资料
贡献者
更新日志
eb6eb
-improve(docs): use pangu formatter于44c43
-improve(docs): use svg picture于43cb2
-improve(docs): use chinese punctuation于25255
-fix(docs): text typo于fea7c
-improve(docs): delete extra whitespace and blank lines于c1c02
-modify(docs): remanage folders and rename files于ec3f5
-docs: update docs于90e37
-docs: update docs于3d6e6
-更改navbar于2d37d
-整理文章代码格式于