跳到主要内容

解析请求参数

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