前言
本文是探讨的是"Go高级之Gin框架中POST参数的提取
"
此文章是个人学习归纳的心得,未经允许,严禁转载,如有不对, 还望斧正, 感谢!
关于POST请求的基础知识
POST请求是一种HTTP请求方法,常用于用于向指定的资源提交要被处理的数据。与GET请求不同,POST请求将数据包含在请求的消息体(body)中,而不是在URL的查询参数中。通过POST请求,可以向服务器发送数据,这些数据可以是表单数据、JSON数据、文件等。
请求的消息体(body)是POST请求中包含的数据部分。它通常用于向服务器发送数据,供服务器进行处理或存储。消息体可以包含各种格式的数据,如表单数据、JSON数据、XML数据等,具体取决于请求的内容类型(Content-Type)。
在HTTP请求中,请求头(headers)中的Content-Type字段用于指示请求的消息体的数据格式。常见的Content-Type类型包括:
- application/x-www-form-urlencoded:用于传输经过URL编码的表单数据,常用于HTML表单提交。
- application/json:用于传输JSON格式的数据。
- multipart/form-data:用于传输带有文件上传的表单数据。
例如,使用POST请求提交表单数据时,请求通常具有以下特征:
- 请求方法:POST
- 请求URL:指定要提交数据的目标资源的URL
- 请求头(headers):Content-Type设置为application/x-www-form-urlencoded或multipart/form-data
- 请求的消息体(body):包含通过表单填写的数据字段和值
示例请求的消息体(body)内容(使用Content-Type为application/x-www-form-urlencoded):
代码语言:txt复制name=John Doe&email=john@example.com&age=25
示例请求的消息体(body)内容(使用Content-Type为application/json):
代码语言:txt复制{
"name": "John Doe",
"email": "john@example.com",
"age": 25
}
通过POST请求和请求的消息体(body),可以向服务器发送数据并执行相应的操作,例如创建新的资源、更新已有资源等。服务器端的代码需要解析请求的消息体,提取相应的数据进行处理。
注意
注意! 无论是表单还是地址栏,默认的请求方式都是GET请求,我们想使用POST请求,一般有两种方法:
- 第一种就是在使用表单的时候,指定请求方式为POST。
- 另外一种就是自己写请求,并且指定请求方法为POST请求。
表单的话,如果不指定为POST请求的话,收集的参数会以get请求中query的形式传给服务器。
在Gin框架中使用数据绑定来提取POST请求的body的数据
手写一个简单的Gin服务器
我们先写一个简单的Gin服务器,其中端口设置为9090
代码语言:txt复制package demo
import (
"fmt"
"github.com/gin-gonic/gin"
)
// 定义结构体,解析post请求携带的body数据,通常使用数据绑定的操作
type UserDemo struct {
Name string `json:"name"`
Age int `json:"age"`
}
func ServerDemo() {
server := gin.Default() // 创建一个gin服务器实例
server.LoadHTMLGlob("demo/HTML/*") // 读取demo文件夹下面的HTML文件夹下面的所有的html文件
//返回index.html
server.GET("/demo", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
//返回index.html
server.GET("/demo2", func(c *gin.Context) {
c.HTML(200, "index2.html", nil)
})
// 定义一个post请求的路由
server.POST("/demo3", func(c *gin.Context) {
user := UserDemo{} //创建一个前面定义好的实例
err := c.ShouldBind(&user) //进行数据绑定,把请求体里面的参数,通过`josn:"name"`和`json:"age"`标识,绑定到结构体的字段中去
fmt.Printf("this is % vn", user)
if err != nil {
c.String(500, "Error")
} else {
c.String(200, "ok")
}
})
server.Run(":9090")
}
HTML部分代码
然后是HTML文件夹下的内容,其中HTML文件夹和上面的go文件是同一级,你看我写的package应该就知道了
这是index.html,就是一个简单的表单,提交的路由是前面定义好了的post路由
代码语言:html复制{{define "index.html"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是demo</h1>
<form action="/demo3" method="post">
<input type="text" name="Name">
<input type="number" name="Age">
<button type="submit">提交</button>
</form>
</body>
</html>
{{end}}
然后是index2.html 这里主要是用axios发了一个post请求
代码语言:txt复制{{ define "index2.html"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<input type="text" name="name">
<input type="number" name="age">
<button type="button">提交2</button>
<script>
document.querySelector("button").addEventListener('click', function(event) {
const name = document.querySelectorAll("input")[0].value
let age = document.querySelectorAll("input")[1].value
console.log('this is is',name,age,typeof age)
axios.post("/demo3",{
Name:name,
Age:age
}).then((response)=>{
console.log(response);
},(error)=>{
console.log(error);
})
});
</script>
</body>
</html>
{{end}}
测试
运行一下
然后我们在浏览器开两个页面,访问一下两个路由
我们先用demo试一下,结果如下,我们成功捕获到了
再用 demo2试一下
小结
在HTML表单中,当使用<form>
元素并设置method
为post
时,浏览器会将表单数据作为请求体的一部分发送到指定的action
URL。请求体的格式是application/x-www-form-urlencoded
,其中包含通过表单中的输入字段收集到的键值对数据。
而使用Axios库发起的POST请求,你可以自定义请求体的数据格式。在我提供的示例中,我使用了Axios的post
方法,并将一个对象作为第二个参数传递。这个对象表示要发送到服务器的数据。Axios默认会将这个对象转换为JSON格式,并将其作为请求体发送。请求的Content-Type会被设置为application/json
。
所以,主要的区别在于请求体的格式和Content-Type。HTML表单使用的是application/x-www-form-urlencoded
格式,而Axios使用的是application/json
格式。
在服务器端,我们可以根据请求的Content-Type选择适当的方式来解析请求体数据。对于application/x-www-form-urlencoded
格式,可以使用c.ShouldBind
或c.ShouldBindWith
方法来解析请求体数据。对于application/json
格式,可以使用c.ShouldBindJSON
方法来解析请求体数据。
但是其实,我们用c.ShouldBind()
就行了,这个函数会先进行Content-Type的判断,然后决定下一步操作
注意
- 在前端界面中,如果不是通过表单来发送post请求的话,而是用axios的话,界面中所有用户输入的东西,格式都是string类型的,你如果要想正确绑定,那你的数据格式就要和type定义的类型一样,感觉有点像是废话,也确实是废话,实际前端开发中,一般是用axios或者什么库,基本上不会使用默认的事件
对了,我近期要用Gin框架 Vue3 js MongoDB写一个个人博客网站的小实践,前后端分离,前后端都是自己来写,我将全程记录,从网站的UI设计,HTML、CSS实现,再到网站的整体架构,再到具体的细节的实现,这也是对Gin框架的一次实践,欢迎关注我的后续动态。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!