一: 请求与请求绑定
1.1: 路径参数
- :参数名, 表示就是取中间的这部分。
- *参数名, 表示取之后的所有数据。
- 路径参数, 用上下文.Param() 获取。
- 案例:
package animal
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/animal/:name/*action", testArgs)
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func testArgs(context *gin.Context) {
name := context.Param("name")
action := context.Param("action")
action = strings.Split(action, "/")[2]
context.String(http.StatusOK, "name is %s, action is %s", name, action)
}
1.2: 查询字符串参数
- DefaultQuery()若参数不村则,返回默认值,Query()若不存在,返回空串。
- DefaultQuery()案例:
package animal
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/animal/login", testArgs)
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
func testArgs(context *gin.Context) {
name := context.DefaultQuery("name", "root")
password := context.DefaultQuery("password", "123456")
context.String(http.StatusOK, "name is %s, password is %s。", name, password)
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
func testArgs(context *gin.Context) {
name := context.Query("name")
password := context.Query("password")
if name == "" || password == "" {
context.String(http.StatusOK, "必要参数缺失")
} else {
context.String(http.StatusOK, "name is %s, password is %s。", name, password)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
1.3: 表单参数
func testArgs(context *gin.Context) {
name := context.PostForm("name")
password := context.PostForm("password")
if name == "" || password == "" {
context.String(http.StatusOK, "必要参数缺失")
} else {
context.String(http.StatusOK, "name is %s, password is %s。", name, password)
}
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
func testArgs(context *gin.Context) {
file, err := context.FormFile("file")
if err != nil {
context.String(500, "file upload fail, err msg is %s", err)
return
}
err = context.SaveUploadedFile(file, file.Filename)
if err != nil {
context.String(500, "file save fail, err msg is %s", err)
return
}
context.String(http.StatusOK, file.Filename)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
1.4:JSON数据
- 参数绑定到结构体上: context.ShouldBindJSON()
- 注意:首先需要实例化一个结构体对象, 然后将这个结构体对象的引用传递进去。
- 为什么必须传递地址?
- 因为实例化的对象, 必须被修改。如果传递对象本质是拷贝一个新的, 不会改变当前的对象。
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
type LoginJsonArgs struct {
Name string `json:"name" binding:"required"`
Password string `json:"password" binding:"required"`
}
func testArgs(context *gin.Context) {
var loginArgs LoginJsonArgs
err := context.ShouldBindJSON(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if loginArgs.Name != "root" && loginArgs.Password != "123456" {
context.JSON(http.StatusUnauthorized, gin.H{"status": "401", "msg": "args validated fail"})
} else {
context.JSON(http.StatusOK, gin.H{"status": "200", "msg": "login success"})
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
1.5: 表单也可以绑定结构体
type LoginJsonArgs struct {
Name string `form:"name" binding:"required"`
Password string `form:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.Bind(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
1.6: 路径参数绑定
type LoginJsonArgs struct {
Name string `uri:"name" binding:"required"`
Password string `uri:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.ShouldBindUri(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/animal/login/:name/:password", testArgs)
}
1.7: 查询字符串绑定
type LoginJsonArgs struct {
Name string `form:"name" binding:"required"`
Password string `form:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.ShouldBindQuery(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
1.8:绑定Header
type LoginJsonArgs struct {
Name string `header:"name" binding:"required"`
Password string `header:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.ShouldBindHeader(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
1.9:用Bind还是ShouldBind方法?
- 区别:Bind如果绑定失败会自动往响应头中加入400的状态码信息。
- 推荐使用ShouldBind,让前端根据返回的响应信息去判断, 而不是用响应头状态码去判断。
二: 响应
2.1: 返回JSON数据
context.JSON(http.StatusOK, gin.H{"status": "200", "msg": "login success"})
2.2: 返回结构体
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
type LoginJsonArgs struct {
Name string `form:"name" binding:"required"`
Password string `form:"password" binding:"required"`
}
func testArgs(context *gin.Context) {
var loginArgs LoginJsonArgs
err := context.ShouldBindQuery(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if loginArgs.Name != "root" && loginArgs.Password != "123456" {
context.JSON(http.StatusUnauthorized, gin.H{"status": "401", "msg": "args validated fail"})
} else {
context.JSON(http.StatusOK, loginArgs)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
2.3: 返回protobuf
reps := []int64{int64(1), int64(2)}
label := "resData"
resData := &protoexample.Test{
Label: &label,
Reps: reps,
}
context.ProtoBuf(200, resData)
2.4: 返回重定向
context.Redirect(http.StatusMovedPermanently, "XXX地址")
三: 异步上下文
- 在异步请求中, 如果要使用上下文, 则必须重新拷贝一下上下文。
package main
import (
"log"
"time"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/long_async", func(c *gin.Context) {
copyContext := c.Copy()
go func() {
time.Sleep(3 * time.Second)
log.Println("异步执行:" + copyContext.Request.URL.Path)
}()
})
r.Run(":8000")
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23