Gin框架操作指南06:POST绑定(下)

官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/

注:没用过Gin的读者强烈建议 先阅读第一节:Gin操作指南:开山篇

本节继续演示POST绑定,包括将request-body绑定到不同的结构体中;映射查询字符串或表单参数;上传文件 Query和post-form。

目录

一、将request-body绑定到不同的结构体中

go 复制代码
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// 定义表单结构体 formA,包含一个必需字段 Foo
type formA struct {
	Foo string `json:"foo" xml:"foo" binding:"required"` // 绑定 JSON 和 XML 的字段 foo
}

// 定义表单结构体 formB,包含一个必需字段 Bar
type formB struct {
	Bar string `json:"bar" xml:"bar" binding:"required"` // 绑定 JSON 和 XML 的字段 bar
}

// 处理请求的函数
func SomeHandler(c *gin.Context) {
	objA := formA{} // 创建 formA 的实例
	objB := formB{} // 创建 formB 的实例

	// c.ShouldBind 使用了 c.Request.Body,不可重用。
	if errA := c.ShouldBind(&objA); errA == nil {
		// 如果绑定成功,返回表单A的成功信息
		c.String(http.StatusOK, `the body should be formA`)
	} else if errB := c.ShouldBind(&objB); errB == nil {
		// 因为现在 c.Request.Body 是 EOF,所以这里会报错。
		c.String(http.StatusOK, `the body should be formB`)
	} else {
		// 处理绑定错误
		c.String(http.StatusBadRequest, `Invalid input`)
	}
}

func main() {
	router := gin.Default()
	router.POST("/some-handler", SomeHandler) // 注册路由
	router.Run(":8080")                       // 启动服务器
}

注意if分支中的注释,效果如下

要想多次绑定,可以使用 c.ShouldBindBodyWith.

func SomeHandler(c *gin.Context) {

objA := formA{}

objB := formB{}

// 读取 c.Request.Body 并将结果存入上下文。

if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {

c.String(http.StatusOK, the body should be formA)

// 这时, 复用存储在上下文中的 body。

} else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {

c.String(http.StatusOK, the body should be formB JSON)

// 可以接受其他格式

} else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {

c.String(http.StatusOK, the body should be formB XML)

} else {

...

}

}

c.ShouldBindBodyWith 会在绑定之前将 body 存储到上下文中。 这会对性能造成轻微影响,如果调用一次就能完成绑定的话,那就不要用这个方法。

只有某些格式需要此功能,如 JSON, XML, MsgPack, ProtoBuf。 对于其他格式, 如 Query, Form, FormPost, FormMultipart 可以多次调用 c.ShouldBind() 而不会造成任任何性能损失 (详见 #1341)。

二、映射查询字符串或表单参数

go 复制代码
package main

import (
	"fmt" // 导入格式化I/O库

	"github.com/gin-gonic/gin" // 导入Gin框架
)

func main() {
	router := gin.Default() // 创建默认的Gin路由

	// 设置处理POST请求的路由
	router.POST("/post", func(c *gin.Context) {

		// c.QueryMap("ids") 用于映射查询字符串中的 "ids" 参数
		// 例如:POST /post?ids[a]=1234&ids[b]=hello
		// 这个方法会将查询参数转换为一个map,key为参数名,value为参数值
		ids := c.QueryMap("ids")

		// c.PostFormMap("names") 用于映射表单数据中的 "names" 参数
		// 例如:names[first]=thinkerou&names[second]=tianou
		// 这个方法会将表单数据转换为一个map
		names := c.PostFormMap("names")

		// 打印解析后的 ids 和 names 的值
		// ids: map[b:hello a:1234], names: map[second:tianou first:thinkerou]
		fmt.Printf("ids: %v; names: %v", ids, names)
	})

	router.Run(":8080") // 启动服务器并监听8080端口
}

打开postman,输入http://localhost:8080/post?ids[a]=1234&ids[b]=hello

然后在body中添加key和value,注意names[]作为一个key,效果如图

三、上传文件

在"上传文件",目录下建立两个文件夹demo01和demo02,demo01用于单文件上传:

go 复制代码
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
	// 将内存限制设置为 8 MiB,这意味着如果上传的文件超过这个大小,
	// 将会返回错误,确保服务器不会因为大文件上传而耗尽内存
	router.MaxMultipartMemory = 8 << 20 // 8 MiB

	// 定义一个 POST 路由,处理文件上传
	router.POST("/upload", func(c *gin.Context) {
		// 从请求中获取文件,"file" 是表单字段的名称
		file, err := c.FormFile("file")
		if err != nil {
			// 处理文件获取错误,返回状态码 400 和错误信息
			c.String(http.StatusBadRequest, "Error retrieving the file")
			return
		}

		// 打印文件名到服务器日志
		log.Println(file.Filename)

		// 设置文件保存的目标路径,文件将保存在当前目录下
		dst := "./" + file.Filename
		// 上传文件至指定的完整文件路径
		if err := c.SaveUploadedFile(file, dst); err != nil {
			// 如果文件保存失败,返回状态码 500 和错误信息
			c.String(http.StatusInternalServerError, "Unable to save the file")
			return
		}

		// 返回成功信息,告知用户文件已上传
		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
	})

	// 启动服务器,监听 8080 端口
	router.Run(":8080")
}

打开postman,输入http://loaclhost:8080/upload,在body中填充form-data,key=file,类型为File,然后选择文件,选好后点击send,效果如下


多文件上传

go 复制代码
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
	// 将内存限制设置为 8 MiB,这意味着如果上传的文件总大小超过这个限制,
	// 将返回错误,确保服务器不会因为大文件上传而耗尽内存
	router.MaxMultipartMemory = 8 << 20 // 8 MiB

	// 定义一个 POST 路由,用于处理文件上传
	router.POST("/upload", func(c *gin.Context) {
		// Multipart form
		// 从请求中获取 multipart 表单数据
		form, err := c.MultipartForm()
		if err != nil {
			// 如果获取 multipart 表单数据失败,返回状态码 400 和错误信息
			c.String(http.StatusBadRequest, "Failed to get multipart form")
			return
		}

		// 获取上传的文件,"upload[]" 是表单字段的名称
		files := form.File["upload[]"]

		// 遍历每个文件
		for _, file := range files {
			// 打印文件名到服务器日志
			log.Println(file.Filename)

			// 设置文件保存的目标路径,文件将保存在当前目录下
			dst := "./" + file.Filename
			// 上传文件至指定目录
			if err := c.SaveUploadedFile(file, dst); err != nil {
				// 如果文件保存失败,返回状态码 500 和错误信息
				c.String(http.StatusInternalServerError, "Unable to save the file")
				return
			}
		}

		// 返回成功信息,告知用户上传的文件数量
		c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
	})

	// 启动服务器,监听 8080 端口
	router.Run(":8080")
}

四、Query和post-form

go 复制代码
package main

import (
	"fmt"

	"github.com/gin-gonic/gin"
)

func main() {
	// 创建一个新的 Gin 路由引擎
	router := gin.Default()

	// 定义一个 POST 路由,用于处理 POST 请求
	router.POST("/post", func(c *gin.Context) {
		// 从查询字符串中获取 "id" 参数
		id := c.Query("id")
		// 从查询字符串中获取 "page" 参数,如果未提供,则返回默认值 "0"
		page := c.DefaultQuery("page", "0")
		// 从 POST 请求的表单数据中获取 "name" 参数
		name := c.PostForm("name")
		// 从 POST 请求的表单数据中获取 "message" 参数
		message := c.PostForm("message")

		// 打印获取到的参数值到标准输出
		fmt.Printf("id: %s; page: %s; name: %s; message: %s\n", id, page, name, message)
	})

	// 启动 HTTP 服务器,监听 8080 端口
	router.Run(":8080")
}

效果

相关推荐
lead520lyq9 小时前
Golang本地内存缓存
开发语言·缓存·golang
小邓吖10 小时前
自己做了一个工具网站
前端·分布式·后端·中间件·架构·golang
码界奇点12 小时前
基于Gin与GORM的若依后台管理系统设计与实现
论文阅读·go·毕业设计·gin·源代码管理
迷迭香与樱花13 小时前
Gin 框架
go·gin
金庆17 小时前
Commit Hash from debug.ReadBuildInfo()
golang
源代码•宸18 小时前
Golang面试题库(sync.Map)
开发语言·后端·面试·golang·map·sync.map·expunged
终生成长者19 小时前
Golang cursorrule
开发语言·后端·golang
席万里19 小时前
基于Go和Vue快速开发的博客系统-快速上手Gin框架
vue.js·golang·gin
源代码•宸20 小时前
Golang面试题库(Map)
后端·面试·golang·map·bmap·hmap·nevacuate
只是懒得想了20 小时前
用Go通道实现并发安全队列:从基础到最佳实践
开发语言·数据库·golang·go·并发安全