除了 JSON、XML 这些标准格式,Gin 还提供了更底层的响应方式,让你可以完全控制响应内容。
最简单的文本响应:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/text", func(c *gin.Context) {
c.String(http.StatusOK, "这是一段纯文本")
})
r.GET("/text/format", func(c *gin.Context) {
name := "张三"
age := 25
c.String(http.StatusOK, "姓名:%s,年龄:%d", name, age)
})
r.Run(":8080")
}
c.Data() 可以返回任意字节流:
r.GET("/binary", func(c *gin.Context) {
data := []byte{0x89, 0x50, 0x4E, 0x47}
c.Data(http.StatusOK, "application/octet-stream", data)
})
c.DataFromReader() 适合流式传输:
r.GET("/stream", func(c *gin.Context) {
file, err := os.Open("large-file.bin")
if err != nil {
c.String(http.StatusInternalServerError, "文件打开失败")
return
}
defer file.Close()
info, _ := file.Stat()
c.DataFromReader(
http.StatusOK,
info.Size(),
"application/octet-stream",
file,
map[string]string{
"Content-Disposition": "attachment; filename=large-file.bin",
},
)
})
Gin 允许直接操作底层的 http.ResponseWriter:
r.GET("/writer", func(c *gin.Context) {
c.Writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
c.Writer.Header().Set("X-Custom-Header", "自定义值")
c.Writer.WriteHeader(http.StatusOK)
c.Writer.Write([]byte("直接写入响应\n"))
c.Writer.Write([]byte("第二行内容"))
})
Server-Sent Events 是一种服务器主动推送的技术:
r.GET("/events", func(c *gin.Context) {
c.Header("Content-Type", "text/event-stream")
c.Header("Cache-Control", "no-cache")
c.Header("Connection", "keep-alive")
for i := 0; i < 10; i++ {
data := fmt.Sprintf("data: 消息 %d\n\n", i)
c.Writer.Write([]byte(data))
c.Writer.Flush()
time.Sleep(time.Second)
}
})
客户端使用 EventSource 接收:
const source = new EventSource('/events');
source.onmessage = function(event) {
console.log(event.data);
};
大量数据时可以流式返回 JSON:
r.GET("/stream/json", func(c *gin.Context) {
c.Header("Content-Type", "application/json")
c.Writer.Write([]byte("["))
first := true
for i := 0; i < 100; i++ {
if !first {
c.Writer.Write([]byte(","))
}
first = false
item := fmt.Sprintf(`{"id":%d,"name":"用户%d"}`, i, i)
c.Writer.Write([]byte(item))
c.Writer.Flush()
time.Sleep(100 * time.Millisecond)
}
c.Writer.Write([]byte("]"))
})
返回特殊格式的内容:
r.GET("/csv", func(c *gin.Context) {
c.Header("Content-Type", "text/csv; charset=utf-8")
c.Header("Content-Disposition", "attachment; filename=data.csv")
csv := "姓名,年龄,城市\n张三,25,北京\n李四,30,上海"
c.String(http.StatusOK, csv)
})
r.GET("/rss", func(c *gin.Context) {
c.Header("Content-Type", "application/rss+xml; charset=utf-8")
rss := `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>我的博客</title>
<link>https://example.com</link>
<item>
<title>文章标题</title>
<description>文章摘要</description>
</item>
</channel>
</rss>`
c.String(http.StatusOK, rss)
})
跳转到其他地址:
r.GET("/redirect", func(c *gin.Context) {
c.Redirect(http.StatusFound, "/target")
})
r.GET("/redirect/external", func(c *gin.Context) {
c.Redirect(http.StatusFound, "https://example.com")
})
根据请求头返回不同内容:
r.GET("/conditional", func(c *gin.Context) {
accept := c.GetHeader("Accept")
switch {
case strings.Contains(accept, "application/json"):
c.JSON(http.StatusOK, gin.H{"message": "JSON 响应"})
case strings.Contains(accept, "application/xml"):
c.XML(http.StatusOK, gin.H{"message": "XML 响应"})
case strings.Contains(accept, "text/html"):
c.HTML(http.StatusOK, "index.html", gin.H{"message": "HTML 响应"})
default:
c.String(http.StatusOK, "文本响应")
}
})
常用的状态码常量:
r.GET("/status", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "成功"})
})
r.GET("/created", func(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{"id": 1, "message": "资源已创建"})
})
r.GET("/no-content", func(c *gin.Context) {
c.Status(http.StatusNoContent)
})
r.GET("/error", func(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
})
r.GET("/not-found", func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"error": "资源不存在"})
})
r.GET("/server-error", func(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "服务器内部错误"})
})
Gin 提供了从高层封装到底层 Writer 的完整响应控制能力。日常开发用 c.JSON() 和 c.String() 就够了,特殊场景可以操作 Writer 实现流式响应、SSE 等功能。选择合适的响应方式,能让 API 更加灵活易用。