• 02-Gin请求参数


    一: 请求与请求绑定

    1.1: 路径参数

    • :参数名, 表示就是取中间的这部分。
    • *参数名, 表示取之后的所有数据。
    • 路径参数, 用上下文.Param() 获取。
    • 案例:
    package animal
    
    import "github.com/gin-gonic/gin"
    
    func Routers(e *gin.Engine) {
    	e.GET("/animal/:name/*action", testArgs)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    package animal
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    	"strings"
    )
    
    func testArgs(context *gin.Context) {
    	// 请求:http://127.0.0.1:8080/animal/dog/jiao/wangwang
    	name := context.Param("name")          // dog
    	action := context.Param("action")      // /jiao/wangwang
    	action = strings.Split(action, "/")[2] // wangwang
    	context.String(http.StatusOK, "name is %s, action is %s", name, action)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    1.2: 查询字符串参数

    • DefaultQuery()若参数不村则,返回默认值,Query()若不存在,返回空串。
    • DefaultQuery()案例:
    package animal
    
    import "github.com/gin-gonic/gin"
    
    func Routers(e *gin.Engine) {
    	e.GET("/animal/login", testArgs)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    package animal
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func testArgs(context *gin.Context) {
    	// 请求: http://127.0.0.1:8080/animal/login?name=dog&password=1234567890
    	name := context.DefaultQuery("name", "root")
    	password := context.DefaultQuery("password", "123456")
    	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
    • Query()案例
    package animal
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func testArgs(context *gin.Context) {
    	// 请求: http://127.0.0.1:8080/animal/login?name=dog&password=1234567890
    	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: 表单参数

    • PostForm()可以解析表单参数
    func testArgs(context *gin.Context) {
    	// 请求:multipart/form-data
    	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)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 表单方式上传文件
    package animal
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func testArgs(context *gin.Context) {
    	// 请求:multipart/form-data
    	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) {
    	// 请求:JSON数据
    	// 获取JSON参数并绑定参数
    	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"`
    }
    
    • 1
    • 2
    • 3
    • 4
    • 绑定的函数采用Bind()
    	var loginArgs LoginJsonArgs
    	err := context.Bind(&loginArgs)
    	if err != nil {
    		context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    		return
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.6: 路径参数绑定

    • 结构体限制绑定方式
    type LoginJsonArgs struct {
    	Name     string `uri:"name" binding:"required"`
    	Password string `uri:"password" binding:"required"`
    }
    
    • 1
    • 2
    • 3
    • 4
    • 绑定函数采用ShouldBindUri()
    	var loginArgs LoginJsonArgs
    	err := context.ShouldBindUri(&loginArgs)
    	if err != nil {
    		context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    		return
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 修改路由
    import "github.com/gin-gonic/gin"
    
    func Routers(e *gin.Engine) {
    	e.GET("/animal/login/:name/:password", testArgs)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.7: 查询字符串绑定

    • 结构体限制绑定参数: 与Form表单一样的。
    type LoginJsonArgs struct {
    	Name     string `form:"name" binding:"required"`
    	Password string `form:"password" binding:"required"`
    }
    
    • 1
    • 2
    • 3
    • 4
    • 修改绑定方式
    	var loginArgs LoginJsonArgs
    	err := context.ShouldBindQuery(&loginArgs)
    	if err != nil {
    		context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    		return
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.8:绑定Header

    • 结构体限制请求头参数
    type LoginJsonArgs struct {
    	Name     string `header:"name" binding:"required"`
    	Password string `header:"password" binding:"required"`
    }
    
    • 1
    • 2
    • 3
    • 4
    • 修改绑定参数
    	var loginArgs LoginJsonArgs
    	err := context.ShouldBindHeader(&loginArgs)
    	if err != nil {
    		context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    		return
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.9:用Bind还是ShouldBind方法?

    • 区别:Bind如果绑定失败会自动往响应头中加入400的状态码信息。
    • 推荐使用ShouldBind,让前端根据返回的响应信息去判断, 而不是用响应头状态码去判断。

    二: 响应

    2.1: 返回JSON数据

    context.JSON(http.StatusOK, gin.H{"status": "200", "msg": "login success"})
    
    • 1

    2.2: 返回结构体

    • 本质也是转换成JSON返回
    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) {
    	// 绑定Header
    	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

    		// 自定义PB格式
    		reps := []int64{int64(1), int64(2)}
    		label := "resData"
    		resData := &protoexample.Test{
    			Label: &label,
    			Reps:  reps,
    		}
    		context.ProtoBuf(200, resData)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.4: 返回重定向

     context.Redirect(http.StatusMovedPermanently, "XXX地址")
    
    • 1

    三: 异步上下文

    • 在异步请求中, 如果要使用上下文, 则必须重新拷贝一下上下文。
    package main
    
    import (
        "log"
        "time"
    
        "github.com/gin-gonic/gin"
    )
    
    func main() {
        r := gin.Default()
        // 1.异步
        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
  • 相关阅读:
    455 - Periodic Strings (UVA)
    python中的关联关系
    Git学习笔记9
    Vue应用API——use解析
    计算机毕业设计SSM城市智能公交系统【附源码数据库】
    计算机毕业设计java+ssm的高校科研仪器共享平台-计算机毕业设计
    【vue】vue3中状态管理Pinia(Vuex5)使用快速上手
    7 个适合初学者的项目,可帮助您开始使用 ChatGPT
    【qemu逃逸】XCTF 华为高校挑战赛决赛-pipeline
    Minio分布式存储系统
  • 原文地址:https://blog.csdn.net/qq_41341757/article/details/126768569