Gin 内置 13 种响应渲染,统一通过Render接口实现。源码位置:render/render.go:9-15type Render interface { Render(http.ResponseWriter) error WriteContentType(w http.ResponseWriter) }1.1 JSON 系列API用途c.JSON(code, obj)标准 JSON,HTML 字符会被转义(→)c.PureJSON(code, obj)不转义,适合返回 HTML 字符串c.IndentedJSON(code, obj)带缩进(便于调试,性能略差)c.SecureJSON(code, obj)加while(1);前缀,防 JSON 劫持c.AsciiJSON(code, obj)非 ASCII 字符转\uXXXXc.JsonpJSON(code, obj)JSONP(配合?callbackxxx)1.1.1 基本使用type User struct { ID int json:id Name string json:name } r.GET(/u, func(c *gin.Context) { c.JSON(200, User{ID: 1, Name: Alice}) }) // {id:1,name:Alice}1.1.2gin.H的本质// gin.go 源码 type H map[string]any所以以下两种写法等价:c.JSON(200, gin.H{id: 1, name: Alice}) c.JSON(200, map[string]any{id: 1, name: Alice})1.1.3 JSONPr.GET(/jsonp, func(c *gin.Context) { data : gin.H{msg: hello} callback : c.Query(callback) if callback { c.JSON(200, data) return } c.JSONP(200, data) // 自动用 callback 包裹 }) // 访问 /jsonp?callbackcb → cb({msg:hello});1.1.4 高性能 JSON源码位置:go.mod引入github.com/bytedance/sonicGin 在支持的平台(amd64 / arm64)上自动使用 sonic,性能比标准库encoding/json高数倍。无需手动开启。1.2 XML / YAML / TOMLr.GET(/xml, func(c *gin.Context) { c.XML(200, gin.H{user: gin.H{id: 1, name: Alice}}) }) r.GET(/yaml, func(c *gin.Context) { c.YAML(200, gin.H{id: 1, name: Alice}) }) r.GET(/toml, func(c *gin.Context) { c.TOML(200, gin.H{id: 1, name: Alice}) })XML struct 标签:xml:tag,如:type User struct { XMLName xml.Name xml:user ID int xml:id,attr Name string xml:name }1.3 Stringr.GET(/, func(c *gin.Context) { c.String(200, hello %s, you are %d, alice, 18) })1.4 HTML 模板1.4.1 准备模板文件templates/index.tmpl:!doctype html html headtitle{{.title}}/title/head body h1{{.title}}/h1 pUser: {{.user.name}} ({{.user.id}})/p ul {{range .items}} li{{.}}/li {{end}} /ul /body /html1.4.2 加载与渲染源码位置:gin.go:270-309r : gin.Default() r.LoadHTMLGlob(templates/*) // 或多个目录 // r.LoadHTMLGlob(templates/*/*) // 或指定文件 // r.LoadHTMLFiles(templates/index.tmpl, templates/about.tmpl) r.GET(/, func(c *gin.Context) { c.HTML(200, index.tmpl, gin.H{ title: 首页, user: gin.H{id: 1, name: Alice}, items: []string{Apple, Banana, Cherry}, }) })1.4.3 不同目录同名模板r.LoadHTMLGlob(templates/**/*) // templates/blog/index.tmpl // templates/admin/index.tmpl // 需要改名注册 r.GET(/blog, func(c *gin.Context) { c.HTML(200, blog/index.tmpl, ...) })1.4.4 自定义模板函数r.SetFuncMap(template.FuncMap{ upper: strings.ToUpper, ts: func(t time.Time) string { return t.Format(2006-01-02 15:04:05) }, }) r.LoadHTMLGlob(templates/*)模板内使用:{{ .name | upper }}、{{ .now | ts }}。⚠️SetFuncMap必须在LoadHTMLGlob之前调用,否则不会生效。1.4.5 嵌入二进制(推荐生产用)import embed //go:embed templates/* var tmplFS embed.FS func main() { r : gin.Default() tmpl, _ : template.ParseFS(tmplFS, templates/*.tmpl) r.SetHTMLTemplate(tmpl) // ... }1.5 文件下载1.5.1 直接返回文件r.GET(/file, func(c *gin.Context) { c.File(./public/report.pdf) })1.5.2 带Content-Disposition(下载)r.GET(/download, func(c *gin.Context) { c.FileAttachment(./public/report.pdf, monthly-report.pdf) })响应头会包含:Content-Disposition: attachment; filenamemonthly-report.pdf1.5.3 流式响应(Reader)适合大文件、动态生成内容:r.GET(/stream, func(c *gin.Context) { pr, pw : io.Pipe() go func() { defer pw.Close() for i : 0; i 10; i { fmt.Fprintf(pw, line %d\n, i) time.Sleep(200 * time.Millisecond) } }() c.Stream(func(w io.Writer) bool { _, err : io.Copy(w, pr) return err nil }) })或使用c.Render:c.Render(200, render.Reader{ ContentType: application/pdf, Reader: someReader, Headers: map[string]string{Content-Disposition: attachment; filenamex.pdf}, })1.6 重定向r.GET(/old, func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, /new) }) // 外部重定向 r.GET(/ext, func(c *gin.Context) { c.Redirect(http.StatusFound, https://example.com) }) // 路由命名重定向(Gin 没有命名路由概念,但可以拼) r.GET(/new, newHandler) r.GET(/shortcut, func(c *gin.Context) { c.Request.URL.Path /new r.HandleContext(c) // 内部转发 })1.7 二进制 / Datar.GET(/bin, func(c *gin.Context) { c.Data(200, application/octet-stream, []byte{0x00, 0x01, 0x02}) }) r.GET(/img, func(c *gin.Context) { b, _ : os.ReadFile(./a.png) c.Data(200, image/png, b) })1.8 ProtoBuf / MsgPack / BSONimport ( github.com/golang/protobuf/proto ) r.GET(/pb, func(c *gin.Context) { msg : mypb.User{Id: 1, Name: Alice} c.ProtoBuf(200, msg) }) r.GET(/msgpack, func(c *gin.Context) { c.MsgPack(200, gin.H{id: 1, name: Alice}) })1.9 Server-Sent Events(SSE)适合向浏览器单向推送数据(聊天、通知、行情)。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) c.Stream(func(w io.Writer) bool { if msg, ok : -someChan; ok { c.SSEvent(message, msg) return true } return false }) })客户端(浏览器 JS):const es new EventSource(/events); es.onmessage e console.log(JSON.parse(e.data));1.10 Cookie 与 SetCookier.GET(/set, func(c *gin.Context) { c.SetSameSite(http.SameSiteLaxMode) c.SetCookie(token, abc123, 3600, /, example.com, true, true) c.String(200, cookie set) }) r.GET(/get, func(c *gin.Context) { token, err : c.Cookie(token) fmt.Println(token, err) })参数:c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)参数说明maxAge秒数,0 表示会话级,0 立即删除secure仅 HTTPS 传输httpOnlyJS 不可读,防 XSS1.11 自定义 Render实现render.Render即可:type CSV struct { Data []User } func (c CSV) ContentType() string { return text/csv; charsetutf-8 } // 实际接口只要求 Render 和 WriteContentType func (c CSV) WriteContentType(w http.ResponseWriter) { w.Header().Set(Content-Type, c.ContentType()) } func (c CSV) Render(w http.ResponseWriter) error { c.WriteContentType(w) ww : csv.NewWriter(w) _ ww.Write([]string{id, name}) for _, u : range c.Data { _ ww.Write([]string{strconv.Itoa(u.ID), u.Name}) } ww.Flush() return nil } // 使用 r.GET(/csv, func(c *gin.Context) { c.Render(200, CSV{Data: []User{{1, Alice}, {2, Bob}}}) })1.12 状态码速查码含义常见场景200 OK成功GET / PUT / PATCH / DELETE201 Created已创建POST 创建资源204 No Content成功无内容DELETE 成功301 / 302重定向资源迁移304 Not Modified资源未变配合 ETag / If-None-Match400 Bad Request客户端参数错误校验失败401 Unauthorized未登录缺失 / 失效 token403 Forbidden无权限已登录但无权限404 Not Found资源不存在409 Conflict冲突唯一约束冲突422 Unprocessable Entity语义错误字段格式正确但语义不通429 Too Many Requests限流限流中间件触发500 Internal Server Error服务端错误兜底502 / 503 / 504网关错误反向代理 / 限流1.13 小结✅ 熟练使用 JSON / XML / YAML / TOML / String✅ 知道c.JSON与c.PureJSON的差异✅ 能用LoadHTMLGlobc.HTML渲染模板✅ 知道c.File/c.FileAttachment/c.Stream的差异✅ 学会自定义 Render(如 CSV)