解析请求参数
uri参数
可以通过Context的Param方法获取uri参数.
package main
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func main(){
r := gin.Default()
r.GET("/user/:name/*action", func(c *gin.Context){
name := c.Param("name")
action := c.Param("action")
// 截取
action = strings.Trim(action, "/")
c.String(http.StatusOK, name + " is " + action)
})
r.Run("0.0.0.0:8001")
}
- 测试:
curl http://192.168.0.10:8001/user/zhangsan/xuexi
# zhangsan is xuexi
查询参数
查询参数可以通过DefaultQuery()
或Query()
方法获取。使用DefaultQuery()
时,若参数不存在,返回默认值。使用Query()
时,如果参数不存在,则返回空串。
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main(){
r := gin.Default()
r.GET("/user", func(c *gin.Context){
name := c.Query("name")
c.JSON(http.StatusOK, gin.H{
"hello": name,
})
})
r.Run("0.0.0.0:8001")
}
- 测试:
curl http://192.168.0.10:8001/user?name=zhangsan
# {"hello":"zhangsan"}
form表单参数
表单传输为 post 请求,http 常见的传输格式有四种:
application/json
application/x-www-form-urlencoded
application/xml
multipart/form-data
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main(){
r := gin.Default()
r.POST("/form", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
}
c.JSON(http.StatusOK, gin.H{
"username": username,
"password": password,
})
r.Run("0.0.0.0:8001")
}
- python测试
import requests
data = {
"username": "zhangsan",
"password": "123456",
}
url = "http://192.168.0.10:8001/v1/loginform"
resp = requests.post(url, data = data)
print(resp.text)
- curl测试:
curl -X POST -d 'username=zhangsan&password=123456' http://192.168.0.10:8001/v1/loginform | python3 -m json.tool
# {
# "password": "123456",
# "username": "zhangsan"
# }
JSON请求体
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 定义接收JSON数据的结构体
type Login struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
func f1(c *gin.Context) {
var json Login
// 将数据解析到结构体中
if err := c.ShouldBindJSON(&json); err != nil {
// 返回错误信息
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"Username": json.Username,
"Password": json.Password,
})
}
func f2(c *gin.Context) {
// 解析未知结构的json请求体
var jsonData map[string]interface{}
if err := c.ShouldBindJSON(&jsonData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 使用 jsonData 处理数据
c.JSON(http.StatusOK, jsonData)
}
func main() {
r := gin.Default()
v1 := r.Group("/v1")
{
v1.POST("/loginjson", f1)
v1.POST("/dynamicjson", f2)
}
r.Run("0.0.0.0:8000")
}
- curl 测试
curl -X POST \
-H 'Content-type:application/json' \
-d '{"username":"zhangsan","password": "qwerty"}' \
http://127.0.0.1:8000/v1/loginjson
# 测试动态请求体
curl -X POST http://127.0.0.1:8000/v1/dynamicjson -d '{"username": "zhangsan", "password": "123456"}'
- python - requests测试
import json
import requests
data_json = {
"username": "zhangsan",
"password": "123456",
}
url = "http://192.168.0.10:8000/v1/loginjson"
resp = requests.post(url, data = json.dumps(data_json))
print(resp.text)
XML请求体
2023年了,不会还有用XML做请求体的吧?不会吧?
- go代码
func f4(c *gin.Context){
// xml数据解 析与绑定
var xml Login
// 将数据解析到结构体中
if err := c.ShouldBindXML(&xml); err != nil {
// 返回错误信息
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"Username": xml.Username,
"Password": xml.Password,
})
}
v1.POST("/loginxml", f4)
- python - requests 测试
import requests
data_xml = """
<?xml version="1.0" encoding="utf-8"?>
<server>
<username>lisi</username>
<password>123456</password>
</server>
"""
url = "http://192.168.0.10:8001/v1/loginxml"
resp = requests.post(url, data = data_xml)
print(resp.text)
上传单个文件
multipart/form-data
格式用于文件上传
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 为 multipart forms 设置文件大小限制, 默认是32MB
// 此处为左移位运算符, 8 * 2的20次方
r.MaxMultipartMemory = 8 << 20 // 8 MiB
r.POST("/upload", func(c *gin.Context) {
// 单文件
file, _ := c.FormFile("file")
log.Println(file.Filename)
// 上传文件至指定的完整文件路径
dst := "./" + file.Filename
c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
r.Run("192.168.0.10:8001")
}
- 测试:
curl -X POST 'http://192.168.0.10:8001/upload' -F "file=@./abc.txt" -H "Content-Type: multipart/form-data"
# 'abc.txt' uploaded!
上传多个文件
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func UploadMultiFile(c *gin.Context){
// 多文件
form, _ := c.MultipartForm()
files := form.File["upload[]"]
for _, file := range files {
log.Println(file.Filename)
// 上传文件至指定的完整文件路径
savePath := "./" + file.Filename
c.SaveUploadedFile(file, savePath)
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
}
func main() {
r := gin.Default()
// 为 multipart forms 设置文件大 小闲置 默认是32MB
// 此处为左移位运算符, 8 * 2的20次方
r.MaxMultipartMemory = 8 << 20 // 8 MiB
r.POST("/uploads", UploadMultiFile)
r.Run("192.168.0.10:8001")
}
- 测试:
curl -X POST 'http://192.168.0.10:8001/uploads' -F "upload[]=@./abc.txt" -F "upload[]=@./bcd.txt" -F "upload[]=@./cde.txt" -H "Content-Type: multipart/form-data"
# 3 files uploaded!
路由组
路由组用于管理一些相同的url。
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func Hello(c *gin.Context){
name := c.Param("name")
c.JSON(http.StatusOK, gin.H{
"hello": name,
})
}
func main() {
r := gin.Default()
v1 := r.Group("/v1")
{
v1.GET("/user/:name", Hello)
}
v2 := r.Group("/v2")
{
v2.GET("/user/:name", Hello)
}
r.Run("192.168.0.10:8001")
}
- 测试:
curl http://192.168.0.10:8001/v1/user/zhangsa
curl http://192.168.0.10:8001/v2/user/lisi