Go 语言 Web 编程系列(十五)

您所在的位置:网站首页 go重定向 Go 语言 Web 编程系列(十五)

Go 语言 Web 编程系列(十五)

2024-07-15 00:11:42| 来源: 网络整理| 查看: 265

1、HTTP 响应报文结构

前面几篇教程我们了解了如何在 Go 语言中解析用户请求信息,包括表单字段和文件上传,接下来,我们来看看处理完请求后,如何将响应发送给客户端。HTTP 响应的报文结构如下所示:

HTTP 响应报文结构

和 HTTP 请求报文结构类似,响应报文也可以分为三部分:状态行、响应头(首部字段)和响应主体。

首先是状态行,在状态行中包含了 HTTP 协议版本和响应状态码,200 OK 表示响应成功,更多状态码信息(常见的有 404、403、500、301 等)可以网上查看下 HTTP 协议或者阅读 HTTP 响应状态码这篇文章了解。

然后是响应头,其中包含了 HTTP 响应的首部字段,比如内容类型/编码、缓存控制、Cookie 信息等。

最后是响应实体,对于 API 接口来说,通常就是返回的 XML/JSON 格式数据,对于 HTML 视图响应,就是一个标准的 HTML 文档,如上图所示。响应头和响应报文之间通过两个换行符分隔。

2、ResponseWriter 接口

在 Go 语言中,客户端请求信息都封装到了 Request 对象,但是发送给客户端的响应并不是 Response 对象,而是 ResponseWriter:

代码语言:javascript复制func Home(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "Welcome to my blog site") }

ResponseWriter 是处理器用来创建 HTTP 响应的接口,其源码结构如下所示:

代码语言:javascript复制type ResponseWriter interface { // 用于设置/获取所有响应头信息 Header() Header // 用于写入数据到响应实体 Write([]byte) (int, error) // 用于设置响应状态码 WriteHeader(statusCode int) }

实际上,在底层支撑 ResponseWriter 的结构体就是 http.response,详见 net/http 包下 server.go 中的 readRequest 方法(调用处理器处理 HTTP 请求时调用了该方法返回响应对象),并且其返回值是 response 指针,这也是为什么在处理器方法声明的时候 Request 是指针类型,而 ResponseWriter 不是,实际上在底层,响应对象也是指针类型(因为在应用代码中需要设置响应头和响应实体,所以响应对象理应是指针类型):

代码语言:javascript复制func (c *conn) readRequest(ctx context.Context) (w *response, err error) { ... w = &response{ conn: c, cancelCtx: cancelCtx, req: req, reqBody: req.Body, handlerHeader: make(Header), contentLength: -1, closeNotifyCh: make(chan bool, 1), wants10KeepAlive: req.wantsHttp10KeepAlive(), wantsClose: req.wantsClose(), } if isH2Upgrade { w.closeAfterReply = true } w.cw.res = w w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize) return w, nil }

response 结构体定义和 ResponseWriter 一样都位于 server.go,感兴趣的同学可以去看下源码,不过由于 response 对外不可见,所以只能通过 ResponseWriter 接口访问它。两者之间的关系是 ResponseWriter 是一个接口,而 http.response 实现了它。当我们引用 ResponseWriter 时,实际上引用的是 http.response 对象实例。

3、设置响应状态码

如上面的 ResponseWriter 接口定义源码所示,它包含三个方法:

WriteHeaderHeaderWrite

WriteHeader 这个方法名有点误导,其实它并不是用来设置响应头的,该方法支持传入一个整型数据用来表示响应状态码,如果不调用该方法的话,默认响应状态码是 200 OK。

WriteHeader 的主要作用是在 API 接口中返回错误码,我们在 goblog/handlers/common.go 中新增一个处理器方法 Error,并通过 w.WriteHeader 返回一个 401 未认证状态码(注意在运行时 w 代表的是对应的 response 对象实例,而不是接口):

代码语言:javascript复制func Error(w http.ResponseWriter, r *http.Request) { w.WriteHeader(401) fmt.Fprintln(w, "认证后才能访问该接口") }

注:这里通过 fmt.Fprintln 将文本字符串写入响应对象。

然后在 routes/web.go 中添加一个路由与之映射:

代码语言:javascript复制WebRoute{ "ApiError", "GET", "/error", handlers.Error, },

重启 HTTP 服务器,通过 curl 访问 http://localhost:8080/error,返回的完整响应报文如下:

可以看到响应状态码是 401 Unauthorized,表示该接口需要认证后才能访问。这里,我们在运行 curl 时带上 -i 选项,以便可以看到完整的响应报文,第一行是响应状态行,然后是响应头信息,响应头每一行是一个键值对映射,通过冒号分隔,左侧是字段名,右侧是字段值,最后是响应实体,也就是我们在代码中写入的响应数据,响应实体和响应头之间通过一个空行分隔(两个换行符)。

5、设置响应头

Header 方法用于设置响应头信息,我们可以通过 w.Header().Set 方法设置响应头(w.Header() 方法返回的是 Header 响应头对象,它和请求头共用一个结构体,因此请求头上支持的方法这里都支持,比如可以通过 w.Header().Add 方法新增响应头),这里我们设置一个 301 重定向响应,只需要通过 w.WriteHeader 方法将响应状态码设置为 301,再通过 w.Header().Set 方法将负责重定向的响应头 Location 设置为一个可访问域名即可。

在 goblog/handlers/common.go 中新建一个处理器方法 Redirect,在其中编写重定向实现代码如下:

代码语言:javascript复制func Redirect(w http.ResponseWriter, r *http.Request) { // 设置一个 301 重定向 w.Header().Set("Location", "https://xueyuanjun.com") w.WriteHeader(301) }

对于重定向请求,无需设置响应实体,另外需要注意的是 w.Header().Set 必须在 w.WriteHeader 之前调用,因为一旦调用 w.WriteHeader 之后,就不能对响应头进行设置了。

接下来,在 routes/web.go 中注册对应的重定向路由:

代码语言:javascript复制WebRoute{ "Redirect", "GET", "/redirect", handlers.Redirect, },

重启 HTTP 服务器,通过 curl 访问该路由可以清楚看到响应被重定向,并且响应实体为空:

如果是在浏览器中访问的话,页面就会跳转到 https://xueyuanjun.com:

6、写入数据到响应实体

Write 方法用于写入数据到 HTTP 响应实体,如果调用 Write 方法时还不知道 Content-Type,会通过数据的前 512 个字节进行判断。

返回文本字符串

以 goblog/handlers/common.go 中定义的 Home 处理器方法为例,我们可以通过 w.Write 写入一段欢迎文本到响应实体:

代码语言:javascript复制func Home(w http.ResponseWriter, r *http.Request) { w.Write([]byte("欢迎访问学院君个人网站?")); }

由于 Write 方法接受的参数类型是 []byte 切片,所以需要将字符串转换为字节切片类型。启动 HTTP 服务器,通过 curl 访问首页,就可以看到返回的文本信息了:

返回 HTML 文档

如果要返回 HTML 文档,可以这么写入响应数据:

代码语言:javascript复制func Home(w http.ResponseWriter, r *http.Request) { //w.Write([]byte("欢迎访问学院君个人网站?")); html := ` 学院君个人网站 欢迎访问学院君个人网站? ` w.Write([]byte(html)) }

当然,后面介绍视图模板后,可以通过视图模板渲染 HTML 文档,这里我们先通过一个简单的包含 HTML 文档信息的字符串替代,重启 HTTP 服务器,通过浏览器访问,就可以看到对应的 HTML 视图了:

此外,由于响应数据的内容类型变成了 HTML,在响应头中,也可以看到 Content-Type 也自动调整成了 text/html,不再是纯文本格式。这里的 Content-Type 就是根据传入的数据自行判断出来的。

返回 JSON 格式数据

当然,我们也可以返回 JSON 格式数据:

代码语言:javascript复制type Greeting struct { Message string `json:"message"` } func Home(w http.ResponseWriter, r *http.Request) { // 返回文本字符串 //w.Write([]byte("欢迎访问学院君个人网站?")); // 返回 HTML 文档 /*html := ` 学院君个人网站 欢迎访问学院君个人网站? ` w.Write([]byte(html))*/ // 返回 JSON 格式数据 greeting := Greeting{ "欢迎访问学院君个人网站?", } message, _ := json.Marshal(greeting) w.Write(message) }

重启 HTTP 服务器,在浏览器中访问 http://localhost:8080:

虽然返回的确实是合法的 JSON 格式数据,但是内容类型依然是 text/plain,而不是 application/json,要返回这个格式的响应头,需要设置响应头才能实现:

代码语言:javascript复制// 返回 JSON 格式数据 greeting := Greeting{ "欢迎访问学院君个人网站?", } message, _ := json.Marshal(greeting) w.Header().Set("Content-Type", "application/json") w.Write(message)

重启 HTTP 服务器,并再次通过 curl 访问首页,就可以看到内容类型变成 application/json 了:



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭