Fork me on GitHub

海纳百川:HTTP的实体数据

我们在前面学到了HTTP报文结构,是由header+body组成。不过我们前面学的知识都还只是停留在header部分,所以现在我们要开始研究body部分。这便引出了HTTP的实体数据概念。

1. 数据类型和编码

在 TCP/IP 协议栈里,传输数据基本上都是“header+body”的格式。但 TCP、UDP 因为是传输层的协议,它们不会关心 body 数据是什么,只要把数据发送到对方就算是完成了任务。

而 HTTP 协议则不同,它是应用层的协议,数据到达之后工作只能说是完成了一半,还必须要告诉上层应用这是什么数据才行,否则上层应用就会“不知所措”。

因此HTTP报文中要包含告知数据类型的义务,不然当浏览器发送一段报文给服务器后,服务器只是到那是一堆报文,至于是什么类型的报文,是文本呢,还是视频呢,还是音频呢,还需要服务器去猜测,就会显得传输效率很低,幸运的是,早在 HTTP 协议诞生之前就已经有了针对这种问题的解决方案,不过它是用在电子邮件系统里的,让电子邮件可以发送 ASCII 码以外的任意数据,方案的名字叫做“多用途互联网邮件扩展”(Multipurpose Internet Mail Extensions),简称为 MIME。因此,HTTP就能顺手牵羊从MIME中拿到自己想要的那部分数据类型 ,这里对HTTP里经常遇到的几种类别:

(1)text:即文本格式的可读数据,我们最熟悉的应该就是 text/html 了,表示超文本文档,此外还有纯文本 text/plain、样式表 text/css 等。
(2)image:即图像文件,有 image/gif、image/jpeg、image/png 等。
(3)audio/video:音频和视频数据,例如 audio/mpeg、video/mp4 等。
(4)application:数据格式不固定,可能是文本也可能是二进制,必须由上层应用程序来解释。常见的有 application/json,application/javascript、application/pdf 等,另外,如果实在是不知道数据是什么类型,像刚才说的“黑盒”,就会是 application/octet-stream,即不透明的二进制数据。

在从MIME中拿到自己想要的数据类型之外,HTTP报文传输还要讲究节约节约带宽,因此这就又涉及到了文件压缩的问题,为了不要让浏览器继续“猜”,还需要有一个“Encoding type”,告诉数据是用的什么编码格式,这样对方才能正确解压缩,还原出原始的数据。比起 MIME type 来说,Encoding type 就少了很多,常用的只有下面三种:

(1)gzip:GNU zip 压缩格式,也是互联网上最流行的压缩格式;
(2)deflate:zlib(deflate)压缩格式,流行程度仅次于 gzip;
(3)br:一种专门为 HTTP 优化的新压缩算法(Brotli)。

 HTTP 协议为此定义了两个 Accept 请求头字段和两个 Content 实体头字段,用于客户端和服务器进行“内容协商”。也就是说,客户端用 Accept 头告诉服务器希望接收什么样的数据,而服务器用 Content 头告诉客户端实际发送了什么样的数据。

 

 

 2. 语言类型与编码

所谓的“语言类型”就是人类使用的自然语言,例如英语、汉语、日语等,而这些自然语言可能还有下属的地区性方言,所以在需要明确区分的时候也要使用“type-subtype”的形式,不过这里的格式与数据类型不同,分隔符不是“/”,而是“-”。举几个例子:en 表示任意的英语,en-US 表示美式英语,en-GB 表示英式英语,而 zh-CN 就表示我们最常使用的汉语。

Accept-Language: zh-CN, zh, en

Content-Language: zh-CN

3. 内容协商的质量值

在 HTTP 协议里用 Accept、Accept-Encoding、Accept-Language 等请求头字段进行内容协商的时候,还可以用一种特殊的“q”参数表示权重来设定优先级,这里的“q”是“quality factor”的意思。权重的最大值是 1,最小值是 0.01,默认值是 1,如果值是 0 就表示拒绝。具体的形式是在数据类型或语言代码后面加一个“;”,然后是“q=value”。q从大到小表示优先级。

Accept: text/html,application/xml;q=0.9,*/*;q=0.8

4. 动手实验

上面讲完了理论部分,接下来就是实际动手操作了。可以用我们的实验环境,在 www 目录下有一个 mime 目录,里面预先存放了几个文件,可以用 URI“/15-1?name=file”的形式访问,例如:

 

 

 这里就给出了响应头字段和请求头字段需求和结果。

5. 课后作业

(1)试着解释一下这个请求头“Accept-Encoding: gzip, deflate;q=1.0, *;q=0.5, br;q=0”,再模拟一下服务器的响应头。

答:请求头希望收到文件的压缩格式是gzip、deflate,除了br之外的其他所有压缩格式,只是如果当这些格式响应头都可以返回的时候,响应头优先响应gzip

和deflate两种格式,其次是其他格式,其中br格式不支持。

服务器响应头模拟:

HTTP/1.1 200 OK
Content-Encoding: gzip......


(2)假设你要使用 POST 方法向服务器提交一些 JSON 格式的数据,里面包含有中文,请求头应该是什么样子的呢?

答:请求头:

Accept-Ranges:bytes
content-type:applicatioon/json
content-language:zh-CN

content-*字段也可以用在请求报文里,说明请求体的数据类型。在这里不能用accept字段,因为是post,所以要用content-language来指明body的语言类型,在content-type里用charset指明编码类型。
至此,结束。

posted @ 2021-02-24 10:26  叶语婷  阅读(104)  评论(0编辑  收藏  举报