前言
Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin。(官方)
下载依赖
1
| go get github.com/gin-gonic/gin
|
引入模块
1
| import "github.com/gin-gonic/gin"
|
获取Engine对象
- 通过
gin.Default()
创建的实例会自带Logger中间件和Recovery中间件
Recovery中间件的作用是:如果程序执行过程中遇到panic中断了服务,则Recovery会恢复程序执行,并返回服务器500内部错 误。
处理HTTP请求
通用的请求处理
处理GET请求
default
:如果没有请求,为变量赋值默认值
1 2 3 4 5 6 7 8 9 10 11
| engine := gin.Default()
engine.Handle("GET", "/", func(context *gin.Context) { value := context.DefaultQuery("key", "default") context.Writer.Write([]byte(value)) })
engine.Run()
|
处理POST请求
1 2 3 4 5 6 7 8 9 10 11
| engine := gin.Default()
engine.Handle("POST", "/", func(context *gin.Context) { value := context.PostForm("key") context.Writer.Write([]byte(value)) })
engine.Run()
|
处理RESTful的DELETE请求
1 2 3 4 5 6 7 8 9 10 11
| engine := gin.Default()
engine.Handle("DELETE", "/:key", func(context *gin.Context) { value := context.Param("key") context.Writer.Write([]byte(value)) })
engine.Run()
|
请求
获取请求行中的数据
获取请求方式
获取请求资源路径
1
| path := context.FullPath();
|
获取请求者的IP地址
获取请求头中的数据
获取指定请求头的数据
<key>
:请求头的键
1
| context.Request.Header.Get("<key>")
|
获取请求携带的参数
获取GET请求的请求参数
1
| value := context.Query("key")
|
指定参数的默认值
default
:如果没有请求,为变量赋值默认值
1
| value := context.DefaultQuery("key", "default")
|
获取POST请求的请求参数
1
| value := context.PostForm("key")
|
参数是否存在
exist
:如果存在指定参数,则返回true;如果不存在指定参数,则返回false
1
| value, exist := context.GetPostForm("key")
|
获取RESTful的请求参数
http://example.com/:key
1
| value := context.Param("key")
|
表单参数实体绑定
传递query参数
request1
| GET http://localhost:8080/api?username=1&password=1
|
1 2 3 4
| type User struct { Username string `form:"username"` Password string `form:"password"` }
|
1 2 3 4 5
| var user User err := context.ShouldBindQuery(&user) if err != nil { log.Fatal(err.Error()) }
|
传递JSON参数
request1 2 3 4
| POST http://localhost:8080/api Content-Type: application/json
{"username": 1, "password": 1}
|
1 2 3 4
| type User struct { Username string `json:"username"` Password string `json:"password"` }
|
1 2 3 4 5
| var user User err := context.ShouldBindJSON(&user) if err != nil { ... }
|
传递uri参数
request1
| GET http://localhost:8080/api/:username/:password
|
1 2 3 4
| type User struct { Username string `uri:"username"` Password string `uri:"password"` }
|
1 2 3 4 5
| var user User err := context.ShouldBindUri(&user) if err != nil { ... }
|
自动映射结构体
- 根据请求头中的
Content-Type
自动映射结构体
1 2 3 4
| type User struct { Username string `form:"username" json:"username"` Password string `form:"password" json:"password"` }
|
1 2 3 4 5
| var user User err := context.ShouldBindJSON(&user) if err != nil { ... }
|
表单参数校验
自定义校验函数
required
:必填项校验
1 2 3 4 5 6 7 8 9 10 11
| type User struct { Username string `form:"username" json:"username" uri:"username" binding:"required"` Password string `form:"password" json:"password" uri:"password" binding:"required,validateFunction"` }
func validateFunction(fieldLevel validator.FieldLevel) bool { if (fieldLevel.field().Interface().(string) == "1") { return false } return true }
|
响应
获取响应行的数据
获取响应状态码
设置响应头的数据
设置指定请求头的数据
<key>
:响应头键
<key>
:响应头值
1
| context.Writer.Header().Set("<key>", "<value>")
|
1
| context.Header("<key>", "<value>")
|
1
| context.Set("<key>", "<value>")
|
设置响应数据
返回字节数组
1
| context.Writer.Writer([]byte(""))
|
返回字符串
1
| context.Writer.WriterString("")
|
返回JSON格式字符串
Map转换为JSON
http.StatusOK
:200
1 2 3 4 5
| context.JSON(http.StatusOK, map[string]interface{}{ "code": 1, "msg": "ok", "data": 数据, })
|
结构体转换为JSON
http.StatusOK
:200
1 2 3 4 5
| type Response struct { Code int Msg string Date interface{} }
|
1 2 3 4 5 6
| resp := Response{ code: 1, message: "ok", data: 数据 } context.JSON(http.StatusOK, &resp)
|
返回HTML页面
传送门
路由组
1 2 3 4 5 6 7 8 9 10 11 12
| engine := gin.Default()
routerGroup := engine.Group("/user") routerGroup.POST("/login", func(context *gin.Context) { context.Writer.WriteString("") }) routerGroup.POST("/register", func(context *gin.Context) { context.Writer.WriteString("") })
engine.Run()
|
抽离路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func main() { engine := gin.Default() routerGroup := engine.Group("/user") routerGroup.POST("/register", register) routerGroup.POST("/login", login) engine.Run()
}
func login(context *gin.Context) { context.Writer.WriteString("") } func register(context *gin.Context) { context.Writer.WriteString("") }
|
中间件
举例:定义一个中间件,用于打印请求方式与请求路径
定义中间件函数
context.Next()
:遇到Next函数立即跳到下一个中间件或请求处理函数
context.Abort()
:遇到Abort函数立即终止后面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| func 中间件函数名() gin.HandlerFunc { return func(context *gin.Context) { if 布尔表达式 { context.Abort() } context.Next()
} }
|
挂载中间件
为全局挂载中间件
printInfo()
:中间件函数
按顺序挂载多个中间件
1
| engine.Use(中间件函数名(), 中间件函数名())
|
1
| engine.Use(中间件函数名()).Use(中间件函数名())
|
为指定处理器挂载中间件
printInfo()
:中间件函数
1 2 3
| engine.Handle("GET", "/", 中间件函数名(), func(context *gin.Context) { ... })
|
为路由组挂载中间件
1 2 3 4 5
| var routerGroup = engine.Group("/") routerGroup.Use(中间件函数名()) routerGroup.GET("", func(context *gin.Context) { ... })
|
文件上传
接收单文件
1 2
| file, err := context.FormFile("key") err := context.SaveUploadedFile(file, "./"+file.Filename)
|
接收多文件
1 2 3 4 5
| form, err := context.MultipartForm() fileList, err := form.File["key_1", "key_2"] for _, file := range fileList { ... }
|
日志
输出位置
仅输出到控制台(缺省值)
1
| gin.DefaultWriter = io.MultiWriter(os.Stdout)
|
仅输出到文件
1 2
| f, err := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f)
|
同时输出到控制台和文件
1 2
| f, err := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(os.Stdout, f)
|
自定义日志格式
1 2 3 4 5 6 7 8 9 10 11 12 13
| router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { return fmt.Sprintf("%s %s %s %s %s %d %s %s %s\n", param.ClientIP, param.TimeStamp.Format(time.RFC1123), param.Method, param.Path, param.Request.Proto, param.StatusCode, param.Latency, param.Request.UserAgent(), param.ErrorMessage, ) }))
|
完成
参考文献
哔哩哔哩——80技术
完美代码
哔哩哔哩——筱筱知晓
哔哩哔哩——go圈里最会写js的奇淼
哔哩哔哩——go圈里最会写js的奇淼
Gin中文文档