18888628835/Blog

Body数据的内容协商

18888628835 opened this issue · 0 comments

Body数据的内容协商

数据类型与编码压缩

在 TCP/IP的协议栈中,传输数据基本上都是 Header+body 的格式,在传输过程中加上各自的头,它们并不关心 body 的数据是什么,只要把数据发送出去就可以了。

HTTP 并不是这样的,它是应用层的协议,数据到达之后的工作只完成了一半,它还必须告诉上层应用这是什么数据。

假设 HTTP 没有告知数据类型的功能,服务器把数据发送给浏览器,那么浏览器该怎么办?

它可以靠猜测,很多数据都是有固定格式的,所以通过代码检查数据的前几个字节也许就可以知道这是个 gif 或者是 mp3文件,但这样做无疑是低效的。

在 HTTP 诞生之前就已经有了针对这种问题的解决方法,这就是应用于电子邮件系统的 MIME(多用途互联网邮件扩展),他可以让电子邮件发送除了 ASCII 码外的数据。

HTTP 借鉴了一部分,用来标记 body 的数据类型,这就是我们经常听到的 MIME type

MIME 把数据分成八类,每个大类下继续分成子类,形式是 type/subtype的字符串,这刚好可以纳入 HTTP 头字段中。

常用类别:

  • text:即文本格式的可读数据,我们常见的就是 text/html,表示超文本文档。此外还有text/plain 和 text/css。

  • image:图像文件,常见 image/gif、image/jpeg、image/png 等。

  • audio/video:音频和视频数据,例如 audio/mpeg、video/mp4等。

  • application:数据格式不固定,由上层应用程序解释。常见的有 application/json、application/JavaScript、application/pdf 等。如果实现不知道数据是什么,就会是 application/octet-stream,即不透明的二进制数据。

在 HTTP 传输时,为了节约带宽,有时候还会压缩数据,为了不让浏览器继续猜,还需要一个 Encoding type,告诉数据是用什么编码格式,这样对方才能够正确解压缩,还原出原始的数据。

比起 MIME typeEncoding type 就少很多,常用的就只有三种:

1.gzip:GNU zip 压缩格式,也是互联网流行的压缩格式。

2.deflate:zlib(deflate)压缩格式,流行程度仅次于 gzip

3.br:专门为 HTTP 优化的新压缩算法。

数据类型使用的头字段

有了 Encoding typeMIME type,服务器和浏览器都可以知道body 数据的类型,那么能不能有一种字段,让双方互相协商,传递对方想要的数据呢?

有的。HTTP 定义了两个 Accept 请求头字段和两个 Content 实体头字段,用于客户端和服务器进行“内容协商”。

其中 Accept(接收)是浏览器告诉服务器希望接收什么样的数据,Content(内容)是服务器告诉浏览器传递过来的数据类型。

请求的头字段

POST /api/base/facade/file/file?action=upload HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br

响应的头字段

HTTP/1.1 200 OK
content-type: application/json;charset=UTF-8
Content-Encoding: gzip

Accept字段标明客户端能够理解的MIME type,上面*/*的意思是都可以理解。多个格式之间使用,分割。

Accept:text/html,application/json

Content-Type字段标明服务器给明的实体数据的类型。这样可以方便浏览器根据数据类型做出处理,比如是 text/html 就可以将它渲染出来。

Accept-Encoding和Content-Encoding分别是浏览器支持的解压缩格式和服务器的实际的压缩格式。

这个过程可以用收发快递来类比,比如我寄出去一个快递告诉我朋友我希望拿到 xxx 类型的东西(Accept),不过这东西我知道我朋友肯定会打包寄给我,所以我告诉他我支持用什么方式来拆包装(Accept-Encoding),我朋友收到后就返回给我某种类型(Content-Type),然后告诉我用指定的方式去拆包装(Content-Encoding)。

语言类型与编码

MIME type 和 Encoding type 解决了计算机理解 body 数据的问题,那么如何解决各国语言的问题呢?

HTTP 引入了语言类型与字符集。

所谓语言类型就是我们使用的汉语、英语、日语等,而语言可能也还有下属的地方语言,所以也是采用 type-subtype的形式,唯一的区别是语言类型用-做分割。

例如:en 表示任意的英语,en-US 则表示美式英语,en-GB 表示英式英语,我们用的 zh-CN 则是汉语。

字符集是为什么而诞生呢?在计算机早期出现了很多语言环境下的字符集,比如英语下的 ASCII 码,汉语下的 GBK 等,为了做到字符的统一,Unicode 诞生了,后来随着互联网的普及,作为 Unicode的实现之一--utf-8大幅度流行,目前 utf-8也成为互联网上的标准字符集。

语言类型使用的头字段

HTTP 同样支持语言类型的 Accept 和 Content 实体头字段。

浏览器用的头字段为 Accept-Language,允许用,分割。

Accept-Language:zh-CN,zh,en

上面的头字段意思是给我zh-CN 的汉语文字,没有的话就给我随便什么汉语,实在不行就给我英文吧。

字符集在请求短则使用 Accept-Charset。

Accept-Charset:utf-8,gbk

服务器使用的头字段为Content-Language,也就是服务器告诉浏览器我传的什么文字类型。

Content-Language:zh-CN

在服务器返回的字符集则是放在 Content-Type字段的后面,用‘charset=xxx’来表示。

Content-Type:text/html;charset=utf-8

现在的浏览器由于功能太强大,一般来说不会发送 Accept-Charset,因为它支持多种字符集,而服务器也不会发送 Content-Language,而是直接告诉浏览器用什么 charset 就行了。

小结

数据类型表示实体数据的内容是什么,使用 MIME type,相关的头部字段为 Accept 和 Content-Type

数据编码表示实体数据的压缩方式,相关的字段为 Accept-Encoding 和 Content-Encoding

语言类型表示实体数据的语言,相关的字段是 Accept-Language 和 Content-Language

字符集是实体数据的编码方式,相关的字段是 Accept-Charset 和 Content-Type