响应处理 #
一、响应类型概述 #
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