711 字
4 分钟
请求和响应处理

请求处理#

绑定 Json 数据#

type User struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required,min=6"`
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"gte=0,lte=130"`
}
func main() {
r := gin.Default()
r.POST("/user", func(c *gin.Context) {
// 绑定 JSON 数据
// 1. 绑定到结构体
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 2. 绑定到 map
var m map[string]any
if err := c.ShouldBindJSON(&m); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 3. 绑定到切片(JSON 数组)
var users []User
if err := c.ShouldBindJSON(&users); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 4. 绑定到 map 切片
var maps []map[string]any
if err := c.ShouldBindJSON(&maps); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 5. 绑定到任意类型(interface{} / any)
var data any
if err := c.ShouldBindJSON(&data); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// 6. 绑定到 json.RawMessage(延迟解析)
var raw json.RawMessage
if err := c.ShouldBindJSON(&raw); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
})
r.Run(":8080")
}

绑定 Xml 数据#

type Article struct {
XMLName xml.Name `xml:"article"`
Title string `xml:"title" binding:"required"`
Content string `xml:"content" binding:"required"`
Author string `xml:"author"`
}
func main() {
r := gin.Default()
r.POST("/article", func(c *gin.Context) {
var article Article
if err := c.ShouldBindXML(&article); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, article)
})
r.Run(":8080")
}

绑定查询参数和表单#

type SearchQuery struct {
Query string `form:"q" binding:"required"`
Page int `form:"page" binding:"gte=1"`
PageSize int `form:"page_size" binding:"gte=1,lte=100"`
Sort string `form:"sort"`
}
func main() {
r := gin.Default()
r.GET("/search", func(c *gin.Context) {
var query SearchQuery
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"query": query.Query,
"page": query.Page,
"page_size": query.PageSize,
"sort": query.Sort,
})
})
r.Run(":8080")
}

绑定 URI 参数#

type UserID struct {
ID int `uri:"id" binding:"required,gte=1"`
}
func main() {
r := gin.Default()
r.GET("/user/:id", func(c *gin.Context) {
var userID UserID
if err := c.ShouldBindUri(&userID); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"user_id": userID.ID,
})
})
r.Run(":8080")
}

响应处理#

Json 响应#

func main() {
r := gin.Default()
// 使用 gin.H
r.GET("/json1", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Hello",
"status": 200,
})
})
// 使用结构体
r.GET("/json2", func(c *gin.Context) {
type Response struct {
Message string `json:"message"`
Status int `json:"status"`
}
c.JSON(http.StatusOK, Response{
Message: "Hello",
Status: 200,
})
})
// 使用 Map
r.GET("/json3", func(c *gin.Context) {
data := map[string]interface{}{
"message": "Hello",
"status": 200,
}
c.JSON(http.StatusOK, data)
})
// SecureJSON(防止 JSON 劫持)
r.GET("/secure-json", func(c *gin.Context) {
c.SecureJSON(http.StatusOK, gin.H{
"data": "sensitive data",
})
})
// JSONP
r.GET("/jsonp", func(c *gin.Context) {
c.JSONP(http.StatusOK, gin.H{
"message": "Hello JSONP",
})
})
// AsciiJSON(转义非 ASCII 字符)
r.GET("/ascii-json", func(c *gin.Context) {
c.AsciiJSON(http.StatusOK, gin.H{
"message": "你好,世界",
})
})
// PureJSON(不转义 HTML 字符)
r.GET("/pure-json", func(c *gin.Context) {
c.PureJSON(http.StatusOK, gin.H{
"html": "<b>Hello</b>",
})
})
r.Run(":8080")
}

Xml 响应#

func main() {
r := gin.Default()
r.GET("/xml", func(c *gin.Context) {
type User struct {
XMLName xml.Name `xml:"user"`
Name string `xml:"name"`
Age int `xml:"age"`
}
c.XML(http.StatusOK, User{
Name: "John",
Age: 30,
})
})
r.Run(":8080")
}

HTML 响应#

func main() {
r := gin.Default()
// 加载 HTML 模板
r.LoadHTMLGlob("templates/*")
r.GET("/html", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"title": "Gin Tutorial",
"name": "John",
})
})
r.Run(":8080")
}

模板文件 templates/index.html

<!DOCTYPE html>
<html>
<head>
<title>{{ .title }}</title>
</head>
<body>
<h1>Hello, {{ .name }}!</h1>
</body>
</html>

重定向#

func main() {
r := gin.Default()
// HTTP 重定向
r.GET("/redirect", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "https://www.google.com")
})
// 路由重定向
r.GET("/old-path", func(c *gin.Context) {
c.Request.URL.Path = "/new-path"
r.HandleContext(c)
})
r.GET("/new-path", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "New path",
})
})
r.Run(":8080")
}

流式响应#

func main() {
r := gin.Default()
r.GET("/stream", func(c *gin.Context) {
c.Stream(func(w io.Writer) bool {
for i := 0; i < 10; i++ {
fmt.Fprintf(w, "data: %d\n\n", i)
time.Sleep(time.Second)
}
return false
})
})
r.Run(":8080")
}
请求和响应处理
https://shirone.mysqil.com/posts/gin/请求和响应处理/
作者
HikariTish
发布于
2026-07-18
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取