Gin是什么
用Go语言编写的高性能HTTP框架.
Gin的特性
- 快速 - 内存占用小, 没有反射
- 支持中间件 - 可以recoverHTTP请求中的panic, 保证服务器始终可用
- JSON验证 - 检查所需的值是否存在
- 路由组 - 更好的组织API, 并且路由组可以无限嵌套
- 错误管理 - 方便收集HTTP请求中的错误, 并写入日志文件
- 内置渲染 - 方便对JSON, XML和HTML的渲染
- 可扩展性 - 可以很方便的新建一个中间件
Gin的安装使用
-
下载并安装Gin
在终端中键入如下命令
go get -u github.com/gin-gonic/gin
-
将Gin引入到工程中
import ( • "github.com/gin-gonic/gin" "net/http" )
-
如果要使用Go语言中定义的状态码, 要引入"net/http"包, 否则不必
例如
http.StatusOK // 就代表200这个常量
下面只是列出"net/http"这个包下的一部分常量定义
StatusOK = 200 // RFC 7231, 6.3.1 StatusCreated = 201 // RFC 7231, 6.3.2 StatusAccepted = 202 // RFC 7231, 6.3.3 StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4 StatusNoContent = 204 // RFC 7231, 6.3.5 StatusResetContent = 205 // RFC 7231, 6.3.6 StatusPartialContent = 206 // RFC 7233, 4.1 StatusMultiStatus = 207 // RFC 4918, 11.1 StatusAlreadyReported = 208 // RFC 5842, 7.1 StatusIMUsed = 226 // RFC 3229, 10.4.1
Gin的简单使用
// 初始化一个Gin路由
r := gin.Default()
// 进行/gin_use的URL注册
r.GET("/gin_use", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": "/gin_use请求成功",
})
})
/*
让Gin进行HTTP请求监听服务
默认端口号: 8080
本机ip地址: 127.0.0.1 / localhost
*/
r.Run()
Gin支持的请求方式
GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS
GET请求中的数据获取
Query & DefaultQuery
r.GET("/user_login", func(c *gin.Context) {
// 查询指定的请求参数,如果没有, 则设置一个默认值
username := c.DefaultQuery("username", "shaosiming")
// 查询指定的请求参数
password := c.Query("password")
c.JSON(200, gin.H{
"username":username,
"password":password,
})
})
ShouldBind
// 定义一个接收数据的结构体
type LoginData struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required"`
}
r.GET("/login", func(context *gin.Context) {
// 声明一个接收数据的结构体变量
var loginData LoginData
// 显式声明绑定方式
//err := context.ShouldBindWith(&loginData, binding.Form)
// 通过一个结构体类型变量来接收数据, 自动绑定
err := context.ShouldBind(&loginData)
if err != nil {
fmt.Println(err)
} else {
// 在这里进行登录逻辑的判断
// 返回一个json格式的数据
context.JSON(200, gin.H{
"username":loginData.Username,
"password":loginData.Password,
"msg":"请求成功",
})
}
})
BindUri
// 定义一个结构体, 用来进行Uri的绑定
type Person struct {
Name string `uri:"name" binding:"required"`
Age int `uri:"age" binding:"required"`
}
r.GET("/bindUri/:name/:age", func(c *gin.Context) {
var person Person
err := c.BindUri(&person)
if err != nil {
c.JSON(400, err.Error())
} else {
c.JSON(200, &person)
}
})
POST请求中的数据获取
PostForm & DefaultPostForm
r.POST("form_post", func(c *gin.Context) {
// 通过指定key从form中取出数据
message := c.PostForm("message")
// 如果form中没有这个key, 则设置一个默认值
nick := c.DefaultPostForm("nick", "shaosiming")
c.JSON(200, gin.H{
"message":message,
"nick":nick,
"msg":"发送成功",
})
})
ShouldBindJSON
r.POST("/bindJSON", func(c *gin.Context) {
var user LoginData
// 请求体为JSON格式的数据, 将其绑定到对应的结构体变量上
err := c.ShouldBindJSON(&user)
if err == nil {
c.JSON(200, &user)
} else {
c.JSON(400, err.Error())
}
})
响应的数据格式
JSON
r.GET("/somejson", func(c *gin.Context) {
c.JSON(200, gin.H{
"code":0,
"msg":"json请求成功",
})
})
struct
// struct
r.GET("/struct", func(c *gin.Context) {
// 定义一个结构体变量
var user struct{
Name string
Age int
}
user.Name = "shaosiming"
user.Age = 18
// 也可以将结构体类型的变量当作返回类型
c.JSON(200, &user)
})
XML
r.GET("/someXML", func(c *gin.Context) {
// 将一个map转换为xml格式进行返回
c.XML(200, gin.H{
"code":0,
"msg":"xml请求成功",
})
})
单个文件的上传
r.POST("/single_upload", func(c *gin.Context) {
// 单个文件的上传
file, err := c.FormFile("file")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(file.Filename)
// 保存到文件目录
dst := "./" + file.Filename
c.SaveUploadedFile(file, dst)
c.JSON(200, gin.H{
"code":0,
"msg":file.Filename + "上传成功",
})
}
})
可以使用curl进行测试
curl -X POST http://localhost:8080/single_upload -F "file=@/Users/Shaosiming/Desktop/test.png" -H "Content-Type: multipart/form-data"
多个文件的上传
r.POST("/multi_upload", func(c *gin.Context) {
form, _ := c.MultipartForm()
// 获取多个文件
files := form.File["upload[]"]
// 将多个文件保存到指定目录
for _, file := range files {
log.Println(file.Filename)
dst := "./" + file.Filename;
c.SaveUploadedFile(file, dst)
}
c.JSON(200, gin.H{
"code":0,
"msg":"多个文件上传成功",
})
})
可以使用curl进行测试
curl -X POST http://localhost:8080/multi_upload -F "upload[]=@/Users/Shaosiming/Desktop/test1.png" -F "upload[]=@/Users/Shaosiming/Desktop/test2.png" -H "Content-Type: multipart/form-data"
路由组的使用
注意: 路由组是可以无限嵌套的哦
// 路由组的使用
v1 := r.Group("/v1")
{
v1.GET("/login", func(c *gin.Context) {
c.JSON(200, gin.H{
"version":1.0,
"msg":"login请求成功",
})
})
v1.GET("/update", func(c *gin.Context) {
c.JSON(200, gin.H{
"version":1.0,
"msg":"update请求成功",
})
})
}
v2 := r.Group("/v2")
{
v2.GET("/login", func(c *gin.Context) {
c.JSON(200, gin.H{
"version":2.0,
"msg":"login请求成功",
})
})
v2.GET("/update", func(c *gin.Context) {
c.JSON(200, gin.H{
"version":2.0,
"msg":"update请求成功",
})
})
}
重定向
// 外部重定向
r.GET("goto_baidu", func(c *gin.Context) {
c.Redirect(301, "https://www.baidu.com/")
})
// 内部重定向
r.GET("/redirect2", func(c *gin.Context) {
c.Redirect(301, "/redirect3")
})
r.GET("/redirect3", func(c *gin.Context) {
c.JSON(200, "direct3")
})
// 路由重定向
r.GET("/redirect4", func(c *gin.Context) {
c.Request.URL.Path = "/redirect5"
r.HandleContext(c)
})
r.GET("/redirect5", func(c *gin.Context) {
c.JSON(200, "direct5")
})