响应处理 #

一、响应类型概述 #

1.1 常用响应类型 #

类型 方法 Content-Type
JSON c.JSON() application/json
XML c.XML() application/xml
HTML c.HTML() text/html
String c.String() text/plain
Data c.Data() 自定义
File c.File() 根据文件类型

1.2 响应流程 #

text
处理函数 → 设置响应头 → 设置状态码 → 写入响应体 → 返回客户端

二、JSON响应 #

2.1 基本用法 #

go
func main() {
    r := gin.Default()
    
    r.GET("/json", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "ok",
            "status":  200,
        })
    })
    
    r.Run()
}

2.2 结构体响应 #

go
type User struct {
    ID    uint   `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func main() {
    r := gin.Default()
    
    r.GET("/user", func(c *gin.Context) {
        user := User{
            ID:    1,
            Name:  "Alice",
            Email: "alice@example.com",
        }
        c.JSON(200, user)
    })
    
    r.Run()
}

2.3 响应数组 #

go
func main() {
    r := gin.Default()
    
    r.GET("/users", func(c *gin.Context) {
        users := []User{
            {ID: 1, Name: "Alice", Email: "alice@example.com"},
            {ID: 2, Name: "Bob", Email: "bob@example.com"},
        }
        c.JSON(200, users)
    })
    
    r.Run()
}

2.4 嵌套JSON #

go
type Response struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
    Meta    *Meta       `json:"meta,omitempty"`
}

type Meta struct {
    Page      int   `json:"page"`
    Size      int   `json:"size"`
    Total     int64 `json:"total"`
    TotalPage int   `json:"totalPage"`
}

func main() {
    r := gin.Default()
    
    r.GET("/list", func(c *gin.Context) {
        users := []User{
            {ID: 1, Name: "Alice"},
            {ID: 2, Name: "Bob"},
        }
        
        c.JSON(200, Response{
            Code:    0,
            Message: "success",
            Data:    users,
            Meta: &Meta{
                Page:      1,
                Size:      10,
                Total:     100,
                TotalPage: 10,
            },
        })
    })
    
    r.Run()
}

2.5 JSONP响应 #

go
func main() {
    r := gin.Default()
    
    r.GET("/jsonp", func(c *gin.Context) {
        data := gin.H{
            "message": "jsonp response",
        }
        c.JSONP(200, data)
    })
    
    // 请求: /jsonp?callback=handleResponse
    // 响应: handleResponse({"message":"jsonp response"})
    
    r.Run()
}

2.6 AsciiJSON #

go
func main() {
    r := gin.Default()
    
    r.GET("/ascii-json", func(c *gin.Context) {
        data := gin.H{
            "message": "中文消息",
            "status":  200,
        }
        c.AsciiJSON(200, data)
    })
    
    // 响应: {"message":"\u4e2d\u6587\u6d88\u606f","status":200}
    
    r.Run()
}

2.7 PureJSON #

go
func main() {
    r := gin.Default()
    
    r.GET("/pure-json", func(c *gin.Context) {
        data := gin.H{
            "html": "<b>Hello</b>",
        }
        c.PureJSON(200, data)
    })
    
    // PureJSON不会转义HTML字符
    
    r.Run()
}

三、XML响应 #

3.1 基本用法 #

go
type User struct {
    XMLName xml.Name `xml:"user"`
    ID      uint     `xml:"id"`
    Name    string   `xml:"name"`
    Email   string   `xml:"email"`
}

func main() {
    r := gin.Default()
    
    r.GET("/xml", func(c *gin.Context) {
        user := User{
            ID:    1,
            Name:  "Alice",
            Email: "alice@example.com",
        }
        c.XML(200, user)
    })
    
    r.Run()
}

3.2 XML响应示例 #

xml
<user>
    <id>1</id>
    <name>Alice</name>
    <email>alice@example.com</email>
</user>

四、HTML响应 #

4.1 基本用法 #

go
func main() {
    r := gin.Default()
    
    // 加载模板
    r.LoadHTMLGlob("templates/*")
    
    r.GET("/index", func(c *gin.Context) {
        c.HTML(200, "index.html", gin.H{
            "title":   "首页",
            "message": "Hello, Gin!",
        })
    })
    
    r.Run()
}

4.2 模板文件 #

templates/index.html:

html
<!DOCTYPE html>
<html>
<head>
    <title>{{ .title }}</title>
</head>
<body>
    <h1>{{ .message }}</h1>
</body>
</html>

4.3 模板继承 #

go
func main() {
    r := gin.Default()
    
    // 加载多级目录模板
    r.LoadHTMLGlob("templates/**/*")
    
    r.GET("/page", func(c *gin.Context) {
        c.HTML(200, "user/index.html", gin.H{
            "title": "用户页面",
        })
    })
    
    r.Run()
}

4.4 模板函数 #

go
func main() {
    r := gin.Default()
    
    // 设置模板函数
    r.SetFuncMap(template.FuncMap{
        "formatDate": func(t time.Time) string {
            return t.Format("2006-01-02 15:04:05")
        },
        "upper": strings.ToUpper,
    })
    
    r.LoadHTMLGlob("templates/*")
    
    r.GET("/date", func(c *gin.Context) {
        c.HTML(200, "date.html", gin.H{
            "now": time.Now(),
        })
    })
    
    r.Run()
}

五、字符串响应 #

5.1 基本用法 #

go
func main() {
    r := gin.Default()
    
    r.GET("/string", func(c *gin.Context) {
        c.String(200, "Hello, World!")
    })
    
    r.Run()
}

5.2 格式化字符串 #

go
func main() {
    r := gin.Default()
    
    r.GET("/format", func(c *gin.Context) {
        name := "Gin"
        version := "1.9.1"
        c.String(200, "框架: %s, 版本: %s", name, version)
    })
    
    r.Run()
}

六、文件响应 #

6.1 返回文件 #

go
func main() {
    r := gin.Default()
    
    r.GET("/file", func(c *gin.Context) {
        c.File("./files/document.pdf")
    })
    
    r.Run()
}

6.2 文件下载 #

go
func main() {
    r := gin.Default()
    
    r.GET("/download", func(c *gin.Context) {
        // 设置下载头
        c.Header("Content-Description", "File Transfer")
        c.Header("Content-Transfer-Encoding", "binary")
        c.Header("Content-Disposition", "attachment; filename=document.pdf")
        c.Header("Content-Type", "application/octet-stream")
        
        c.File("./files/document.pdf")
    })
    
    r.Run()
}

6.3 文件流 #

go
func main() {
    r := gin.Default()
    
    r.GET("/stream", func(c *gin.Context) {
        file, err := os.Open("./files/video.mp4")
        if err != nil {
            c.String(500, "File not found")
            return
        }
        defer file.Close()
        
        fileInfo, _ := file.Stat()
        
        c.Header("Content-Type", "video/mp4")
        c.Header("Content-Length", strconv.FormatInt(fileInfo.Size(), 10))
        c.Header("Content-Disposition", "inline; filename=video.mp4")
        
        io.Copy(c.Writer, file)
    })
    
    r.Run()
}

6.4 Reader响应 #

go
func main() {
    r := gin.Default()
    
    r.GET("/reader", func(c *gin.Context) {
        reader := strings.NewReader("Hello from reader!")
        
        c.DataFromReader(200, "text/plain", reader, map[string]string{
            "Content-Disposition": `attachment; filename="hello.txt"`,
        })
    })
    
    r.Run()
}

七、Data响应 #

7.1 基本用法 #

go
func main() {
    r := gin.Default()
    
    r.GET("/data", func(c *gin.Context) {
        data := []byte("Hello, Data!")
        c.Data(200, "text/plain", data)
    })
    
    r.Run()
}

7.2 二进制数据 #

go
func main() {
    r := gin.Default()
    
    r.GET("/binary", func(c *gin.Context) {
        data := []byte{0x89, 0x50, 0x4E, 0x47} // PNG文件头
        c.Data(200, "image/png", data)
    })
    
    r.Run()
}

八、响应头和状态码 #

8.1 设置响应头 #

go
func main() {
    r := gin.Default()
    
    r.GET("/headers", func(c *gin.Context) {
        c.Header("X-Custom-Header", "value")
        c.Header("X-Request-Id", "12345")
        c.Header("Cache-Control", "no-cache")
        
        c.JSON(200, gin.H{"message": "ok"})
    })
    
    r.Run()
}

8.2 设置状态码 #

go
func main() {
    r := gin.Default()
    
    r.GET("/status", func(c *gin.Context) {
        c.Status(200)
        c.String(200, "OK")
    })
    
    r.GET("/created", func(c *gin.Context) {
        c.JSON(201, gin.H{"message": "created"})
    })
    
    r.GET("/no-content", func(c *gin.Context) {
        c.Status(204)
    })
    
    r.Run()
}

8.3 常用状态码 #

状态码 说明 使用场景
200 OK 成功响应
201 Created 创建成功
204 No Content 删除成功
400 Bad Request 请求参数错误
401 Unauthorized 未认证
403 Forbidden 无权限
404 Not Found 资源不存在
500 Internal Server Error 服务器错误

8.4 重定向 #

go
func main() {
    r := gin.Default()
    
    // 临时重定向 (302)
    r.GET("/redirect", func(c *gin.Context) {
        c.Redirect(302, "/new-url")
    })
    
    // 永久重定向 (301)
    r.GET("/permanent", func(c *gin.Context) {
        c.Redirect(301, "/new-url")
    })
    
    r.GET("/new-url", func(c *gin.Context) {
        c.String(200, "New URL")
    })
    
    r.Run()
}

九、统一响应格式 #

9.1 响应结构体 #

go
type Response struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

func Success(c *gin.Context, data interface{}) {
    c.JSON(200, Response{
        Code:    0,
        Message: "success",
        Data:    data,
    })
}

func Error(c *gin.Context, code int, message string) {
    c.JSON(200, Response{
        Code:    code,
        Message: message,
    })
}

func Created(c *gin.Context, data interface{}) {
    c.JSON(201, Response{
        Code:    0,
        Message: "created",
        Data:    data,
    })
}

func NoContent(c *gin.Context) {
    c.Status(204)
}

9.2 使用示例 #

go
func main() {
    r := gin.Default()
    
    r.GET("/success", func(c *gin.Context) {
        Success(c, gin.H{"name": "Gin"})
    })
    
    r.GET("/error", func(c *gin.Context) {
        Error(c, 1001, "参数错误")
    })
    
    r.POST("/create", func(c *gin.Context) {
        Created(c, gin.H{"id": 1})
    })
    
    r.DELETE("/delete", func(c *gin.Context) {
        NoContent(c)
    })
    
    r.Run()
}

十、总结 #

10.1 核心要点 #

要点 说明
JSON响应 c.JSON()
XML响应 c.XML()
HTML响应 c.HTML()
文件响应 c.File()
响应头 c.Header()
状态码 c.Status()

10.2 最佳实践 #

实践 说明
统一格式 使用统一的响应结构
正确状态码 使用合适的HTTP状态码
错误处理 统一错误响应格式
响应头 设置必要的安全头

10.3 下一步 #

现在你已经掌握了响应处理,接下来让我们学习 Cookie与Session,了解会话管理!

最后更新:2026-03-28