Gin框架基础篇003_响应设置详解(状态码、头信息、多格式应答体)

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(如果没有设置的话)。
  • 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>&lt;h1&gt;hello world&lt;/h1&gt;</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&amp;tpl=mn&amp;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>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <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,返回布尔值控制是否继续流式传输
    • 使用场景: 大文件下载、实时日志输出、长时间运行的任务状态更新
    • 特点: 支持持续的数据传输,适合需要长时间保持连接的场景
相关推荐
IT_陈寒2 小时前
Python性能调优实战:5个不报错但拖慢代码300%的隐藏陷阱(附解决方案)
前端·人工智能·后端
Grassto2 小时前
Go Module 基础概念全解析:module、version、sum 是什么
golang·go·go module
JaguarJack2 小时前
成为高级 PHP 开发者需要的思维转变
后端·php·服务端
BingoGo2 小时前
成为高级 PHP 开发者需要的思维转变
后端·php
悟能不能悟2 小时前
Spring HATEOAS 详细介绍
java·后端·spring
源代码•宸2 小时前
goframe框架签到系统项目开发(用户认证中间件、实现Refresh-token接口)
数据库·经验分享·后端·算法·中间件·跨域·refreshtoken
Victor3562 小时前
Hibernate(5)什么是Hibernate的配置文件?
后端
努力也学不会java2 小时前
【Spring Cloud】初识Spring Cloud
运维·人工智能·后端·spring·机器学习·spring cloud
Qiuner2 小时前
Spring Boot AOP(五) 高级特性与源码实践
java·spring boot·后端