Gin框架中的Context为我们提供了多种多样的方法,来设置应答状态码、应答头信息、应答体消息!并且为了方便开发者,Gin框架提供了多种应答体格式的便捷处理方法,比如JSON、TOML、XML...
1. 状态码
Gin框架提供了func (c *Context) Status(code int)方法来设置应答的状态码。
- 如果没有显式调用,那么默认会写入
http.statusOK状态码。
除了该方法外,很多Gin框架设置应答体的方法也会带有一个状态码参数,用于在设置应答体的同时设置应答码。后文会介绍~
go
// 示例
c.Status(http.StatusBadRequest)
2. 头信息
2.1. 设置普通Header
Gin框架提供了func (c *Context) Header(key, value string)方法来设置应答的请求头。
- 底层调用
c.Writer.Header().Set(key, value)设置请求头。 - 如果参数value为空,则表示删除指定key请求头信息。
go
// 示例
c.Header("ClientID", "12345678")
2.2. 设置Cookie
对于设置cookie这种常见场景,Gin框架提供了如下两个方法来方便我们设置cookie:
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)func (c *Context) SetCookieData(cookie *http.Cookie)
go
// SetCookie 示例
c.SetCookie("token", "12345678", 3600, "/", "hello.com", false, true)
// SetCookieData示例
c.SetCookieData(&http.Cookie{
Name: "token",
Value: url.QueryEscape("12345678"),
MaxAge: 3600,
Path: "/",
Domain: "hello.com",
SameSite: http.SameSiteDefaultMode,
Secure: false,
HttpOnly: true,
})
3. 应答体
Gin框架针对不同的应答体格式,提供了对应的便捷方法供开发者使用~
3.1. 常用格式
Gin针对字符串、JSON、TOML、XML、YAML这些常用的应答体格式,提供了专门的便捷性方法:
- 字符串
func (c *Context) String(code int, format string, values ...any)
- JSON
func (c *Context) AsciiJSON(code int, obj any)func (c *Context) IndentedJSON(code int, obj any)func (c *Context) JSON(code int, obj any)func (c *Context) JSONP(code int, obj any)func (c *Context) PureJSON(code int, obj any)func (c *Context) SecureJSON(code int, obj any)
- TOML
func (c *Context) TOML(code int, obj any)
- XML
func (c *Context) XML(code int, obj any)
- YAML
func (c *Context) YAML(code int, obj any)
3.1.1. String
func (c *Context) String(code int, format string, values ...any)方法向应答体中写入字符串格式的消息:
- code参数用于设置应答状态码。
- 方法支持字符串格式化,底层使用的是
fmt格式化包。 - 如果没有设置
Content-Type请求头,该方法会自动设置为"text/plain; charset=utf-8".
go
// 示例
c.String(http.StatusOK, "Hello World: %s", time.Now().Format("2006-01-02 15:04:05"))
3.1.2. JSON
JSON格式相关方法:
func (c *Context) JSON(code int, obj any)- 以JSON格式序列化obj,然后将结果写入应答体,并设置设置Content-Type为
application/json; charset=utf-8(如果没有设置的话)。
- 以JSON格式序列化obj,然后将结果写入应答体,并设置设置Content-Type为
func (c *Context) AsciiJSON(code int, obj any)- 与
JSON方法相似,区别在于会将其中的unicode字符转换为ASCII字符。
- 与
func (c *Context) IndentedJSON(code int, obj any)- 与
JSON方法相似,区别在于会序列化成更方便阅读的JSON(带缩紧和结束行)。
- 与
func (c *Context) JSONP(code int, obj any)- 与JSON方法相似,但会根据请求参数决定返回格式,支持JSONP跨域请求。
func (c *Context) PureJSON(code int, obj any)- 与JSON方法类似,为纯净的JSON响应格式,不进行任何特殊的安全处理。
func (c *Context) SecureJSON(code int, obj any)- 与JSON方法类似,为增强安全性的JSON响应格式,主要用于防止JSON劫持攻击
示例:
仅用于演示,正常不会这么写
go
func TestJson(c *gin.Context) {
data := Data{
ID: 1,
Name: "hello",
LongName: "abc123!@#你好",
Html: "<h1>hello world</h1>",
}
c.JSON(http.StatusOK, data)
c.AsciiJSON(http.StatusOK, data)
c.IndentedJSON(http.StatusOK, data)
c.JSONP(http.StatusOK, data)
c.PureJSON(http.StatusOK, data)
c.SecureJSON(http.StatusOK, data)
}
请求:
http
GET /resp/json?callback=abc HTTP/1.1
Host: 127.0.0.1:8080
输出:
json
// JSON
[{"name":"abc123!@#你好","html":"\u003ch1\u003ehello world\u003c/h1\u003e"}]
// AsciiJSON
[{"name":"abc123!@#\u4f60\u597d","html":"\u003ch1\u003ehello world\u003c/h1\u003e"}]
// IndentedJSON
[
{
"name": "abc123!@#你好",
"html": "\u003ch1\u003ehello world\u003c/h1\u003e"
}
]
// JSONP
abc([{"name":"abc123!@#你好","html":"\u003ch1\u003ehello world\u003c/h1\u003e"}]);
// PureJSON
[{"name":"abc123!@#你好","html":"<h1>hello world</h1>"}]
// SecureJSON
while(1);[{"name":"abc123!@#你好","html":"\u003ch1\u003ehello world\u003c/h1\u003e"}]
3.1.3. TOML
Gin框架提供了func (c *Context) TOML(code int, obj any)方法来便于处理TOML格式应答。
示例:
go
func TestToml(c *gin.Context) {
data := struct {
Name string `toml:"name"`
Html string `toml:"html"`
}{
Name: "abc123!@#你好",
Html: "<h1>hello world</h1>",
}
c.TOML(http.StatusOK, data)
}
应答:
toml
name = 'abc123!@#你好'
html = '<h1>hello world</h1>'
3.1.4. XML
Gin框架提供了func (c *Context) XML(code int, obj any)方法来便于处理XML格式应答。
示例:
go
// xml不支持匿名结构体
type XmlData struct {
Name string `xml:"name"`
Html string `xml:"html"`
}
func TestXml(c *gin.Context) {
data := XmlData{
Name: "abc123!@#你好",
Html: "<h1>hello world</h1>",
}
c.XML(http.StatusOK, data)
}
应答:
xml
<XmlData><name>abc123!@#你好</name><html><h1>hello world</h1></html></XmlData>
3.1.5. YAML
Gin框架提供了func (c *Context) YAML(code int, obj any)方法来便于处理YAML格式应答。
示例:
go
func TestYaml(c *gin.Context) {
data := struct {
Name string `yaml:"name"`
Html string `yaml:"html"`
}{
Name: "abc123!@#你好",
Html: "<h1>hello world</h1>",
}
c.YAML(http.StatusOK, data)
}
应答:
yaml
name: "abc123!@#你好"
html: <h1>hello world</h1>
3.2. 设置字节数组
func (c *Context) Data(code int, contentType string, data []byte)方法用于直接向应答体中写入字节数组。
- code 参数指定状态码。
- contentType 指定Content-Type头信息
- data 数据
示例:
go
func TestBytes(c *gin.Context) {
c.Data(http.StatusOK, "text/plain", []byte("hello world"))
}
应答:
hello world
3.3. 从Reader流中读取数据返回
func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string)方法用于直接从Reader中读取数据,然后向应答中写入读取到的数据。
- code 参数指定状态码。
- contentLength 用于设置Content-Length头信息
- contentType 指定Content-Type头信息
- reader 数据来源的流
- extraHeaders 指定其他的头信息
示例:
go
func TestReader(c *gin.Context) {
req, _ := http.NewRequest("GET", "https://www.baidu.com", nil)
response, err := http.DefaultClient.Do(req)
if err != nil {
c.String(http.StatusInternalServerError, "error")
return
}
c.DataFromReader(http.StatusOK, response.ContentLength, response.Header.Get("Content-Type"), response.Body, nil)
}
应答:
html
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
3.4. 下载文件
Gin 框架的 Context 提供了几个用于处理文件的方法,包括 File、FileAttachment 和 FileFromFS。下面详细介绍这些方法:
func (c *Context) File(filepath string)- 功能:直接将指定路径的文件发给客户端
- 用途:用于将本地文件作为 HTTP 响应发送
- 特点:
- 直接使用操作系统的文件路径
- 设置适当的 Content-Type 头部
- 自动处理文件不存在的情况
func (c *Context) FileAttachment(filepath, filename string)- 功能:直接将指定路径的文件以附件的形式发给客户端,让浏览器下载文件。
- 用途:用于浏览器下载服务器文件。
- 特点:
- 在 Content-Disposition 头部设置 attachment,提示浏览器下载
- 可以指定下载时的文件名,与服务器路径名可以不同
- 同样会自动设置 Content-Type
func (c *Context) FileFromFS(filepath string, fs http.FileSystem)- 功能:从指定的文件系统中发送文件
- 参数:
- filepath:在文件系统中的路径
- fs:http.FileSystem 接口的实现
- 用途:
- 用于从自定义文件系统(如嵌入资源、内存文件系统等)提供文件
- 适用于需要从非标准文件系统提供文件的场景
- 可以用于提供嵌入到二进制文件中的静态资源
使用示例:
go
// 直接发送服务器上的文件
c.File("/path/to/file.txt")
// 强制下载文件,下载时显示为 custom-name.txt
c.FileAttachment("/path/to/server-file.txt", "custom-name.txt")
// 从自定义文件系统发送文件
customFS := http.Dir("./static")
c.FileFromFS("index.html", customFS)
这些方法为 Gin 应用提供了灵活的文件服务功能,可以根据不同需求选择合适的方法来提供文件服务。
3.5. 其他
Gin还提供了下面这些应答相关的方法,由于不太常用,此处不去详细讲解:
当然,后续可也能在专门的博客中去单独讲解。
-
func (c *Context) HTML(code int, name string, obj any)- 功能: 渲染 HTML 模板并返回给客户端
- 参数:
- code: HTTP 状态码
- name: 模板名称
- obj: 传递给模板的数据
- 使用场景: Web 应用程序返回 HTML 页面,如网站页面、管理后台等
-
func (c *Context) Negotiate(code int, config Negotiate)- 功能: 根据客户端 Accept 头进行内容协商,返回适当格式的响应
- 参数:
- code: HTTP 状态码
- config: 包含不同响应格式配置的 Negotiate 结构体
- 使用场景: API 服务需要根据客户端请求支持多种响应格式(JSON、XML、HTML 等)
- 特点: 智能选择最适合客户端的响应格式
-
func (c *Context) ProtoBuf(code int, obj any)- 功能: 将数据序列化为 Protocol Buffers 格式并返回
- 参数:
- code: HTTP 状态码
- obj: 要序列化的数据对象
- 使用场景: 高性能 API 服务、微服务间通信、需要高效序列化的场景
- 优势: 比 JSON 更高效、体积更小
-
func (c *Context) Render(code int, r render.Render)- 功能: 使用指定的渲染器返回响应,是其他渲染方法的基础
- 参数:
- code: HTTP 状态码
- r: 实现了 render.Render 接口的渲染器
- 使用场景: 自定义响应格式、需要灵活控制响应内容的场景
- 特点: 通用渲染方法,支持多种内置和自定义渲染器
-
func (c *Context) SSEvent(name string, message any)- 功能: 发送 Server-Sent Events (SSE) 消息
- 参数:
- name: 事件名称
- message: 事件数据
- 使用场景: 实时数据推送、实时通知、实时更新等需要服务端向客户端推送数据的场景
- 特点: 单向实时通信,客户端可接收服务端推送的事件
-
func (c *Context) Stream(step func(w io.Writer) bool) bool- 功能: 流式传输响应数据,逐步向客户端发送数据
- 参数:
- step: 一个函数,接收 io.Writer,返回布尔值控制是否继续流式传输
- 使用场景: 大文件下载、实时日志输出、长时间运行的任务状态更新
- 特点: 支持持续的数据传输,适合需要长时间保持连接的场景