表单参数通常通过 POST 请求提交,有两种格式:
application/x-www-form-urlencoded和multipart/form-data。Gin 都支持。
使用 PostForm() 获取表单字段:
r.POST("/login", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
c.JSON(200, gin.H{
"username": username,
"password": password,
})
})
DefaultPostForm() 设置默认值:
r.POST("/submit", func(c *gin.Context) {
name := c.DefaultPostForm("name", "Anonymous")
email := c.DefaultPostForm("email", "")
c.JSON(200, gin.H{
"name": name,
"email": email,
})
})
GetPostForm() 可以区分空值和不存在:
r.POST("/submit", func(c *gin.Context) {
email, exists := c.GetPostForm("email")
if !exists {
c.JSON(400, gin.H{"error": "缺少 email 字段"})
return
}
c.JSON(200, gin.H{"email": email})
})
PostFormMap() 返回所有表单字段:
r.POST("/submit", func(c *gin.Context) {
form := c.PostFormMap()
()
for key, values := range form {
for _, value := range values {
fmt.Printf("%s = %s\n", key, value)
}
}
c.JSON(200, form)
})
表单可以有同名字段:
r.POST("/submit", func(c *gin.Context) {
tags := c.PostFormArray("tags")
c.JSON(200, gin.H{"tags": tags})
})
HTML 表单:
<form method="POST" action="/submit">
<input type="text" name="tags" value="go">
<input type="text" name="tags" value="web">
<input type="text" name="tags" value="api">
<button type="submit">提交</button>
</form>
multipart/form-data 用于文件上传:
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{
"filename": file.Filename,
"size": file.Size,
"header": file.Header,
})
})
import "os"
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
dst := "./uploads/" + file.Filename
err = c.SaveUploadedFile(file, dst)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{
"message": "文件上传成功",
"filename": file.Filename,
})
})
r.POST("/upload", func(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
files := form.File["files"]
for _, file := range files {
dst := "./uploads/" + file.Filename
c.SaveUploadedFile(file, dst)
}
c.JSON(200, gin.H{
"message": "文件上传成功",
"count": len(files),
})
})
type LoginForm struct {
Username string `form:"username" binding:"required"`
Password string `form:"password" binding:"required,min=6"`
}
r.POST("/login", func(c *gin.Context) {
var form LoginForm
if err := c.ShouldBind(&form); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if form.Username == "admin" && form.Password == "password123" {
c.JSON(200, gin.H{
"message": "登录成功",
"token": "xxx",
})
} else {
c.JSON(401, gin.H{
"error": "用户名或密码错误",
})
}
})
type RegisterForm struct {
Username string `form:"username" binding:"required,min=3,max=20"`
Email string `form:"email" binding:"required,email"`
Password string `form:"password" binding:"required,min=6"`
}
r.POST("/register", func(c *gin.Context) {
var form RegisterForm
if err := c.ShouldBind(&form); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(201, gin.H{
"message": "注册成功",
"username": form.Username,
"email": form.Email,
})
})
r.POST("/profile", func(c *gin.Context) {
name := c.PostForm("name")
avatar, err := c.FormFile("avatar")
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
dst := "./uploads/" + avatar.Filename
c.SaveUploadedFile(avatar, dst)
c.JSON(200, gin.H{
"name": name,
"avatar": avatar.Filename,
"message": "个人资料更新成功",
})
})
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.POST("/login", login)
r.POST("/register", register)
r.POST("/upload", upload)
r.Run(":8080")
}
func login(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
if username == "" || password == "" {
c.JSON(http.StatusBadRequest, gin.H{
"error": "用户名和密码不能为空",
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "登录成功",
"username": username,
})
}
func register(c *gin.Context) {
username := c.PostForm("username")
email := c.PostForm("email")
password := c.PostForm("password")
if username == "" || email == "" || password == "" {
c.JSON(http.StatusBadRequest, gin.H{
"error": "所有字段都必须填写",
})
return
}
c.JSON(http.StatusCreated, gin.H{
"message": "注册成功",
"username": username,
"email": email,
})
}
func upload(c *gin.Context) {
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "请选择要上传的文件",
})
return
}
if file.Size > 10*1024*1024 {
c.JSON(http.StatusBadRequest, gin.H{
"error": "文件大小不能超过 10MB",
})
return
}
dst := "./uploads/" + file.Filename
err = c.SaveUploadedFile(file, dst)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "文件保存失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "文件上传成功",
"filename": file.Filename,
"size": file.Size,
})
}
这一章学习了:
PostForm() 获取表单字段DefaultPostForm() 设置默认值FormFile() 处理文件上传SaveUploadedFile() 保存上传的文件