数据类型与编码

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

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

假设 HTTP 没有奉告数据类型的功能,服务器把“一大坨”数据发给了浏览器,这时分该怎么办呢?

它能够“猜”。由于许多数据都是有固定格局的,所以通过查看数据的前几个字节或许能知道这是个 GIF 图片、或者是个 MP3 音乐文件,但这种方法无疑非常低效,而且有很大几率会查看不出来文件类型。

幸运的是,早在 HTTP 协议诞生之前就已经有了针对这种问题的解决方案,不过它是用在电子邮件系统里的,让电子邮件能够发送 ASCII 码以外的恣意数据,方案的姓名叫做多用途互联网邮件扩展,简称为 MIME。

MIME 是一个很大的规范规范,但 HTTP 只“顺手牵羊”取了其中的一部分,用来符号 body 的数据类型,这便是我们平常总能听到的“MIME type”。

MIME 把数据分成了八大类,每个大类下再细分出多个子类,方法是type/subtype的字符串,刚好契合 HTTP 明文的特点,所以能够很容易地归入 HTTP 头字段里。

这里简单列举一下在 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 type 还不行,由于 HTTP 在传输时为了节省带宽,有时分还会紧缩数据,为了不要让浏览器持续“猜”,还需要有一个“Encoding type”,告知数据是用的什么编码格局,这样对方才能正确解紧缩,还原出原始的数据。

Encoding type 常用的只有下面三种:

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

数据类型运用的头字段

有了 MIME type 和 Encoding type,无论是浏览器还是服务器就都能够轻松识别出 body 的类型,也就能够正确处理数据了。

HTTP 协议为此界说了两个 Accept 恳求头字段和两个 Content 实体头字段,用于客户端和服务器进行“内容洽谈”。也便是说,客户端用 Accept 头告知服务器期望接纳什么样的数据,而服务器用 Content 头告知客户端实践发送了什么样的数据。

HTTP(13):Body的数据

Accept字段符号的是客户端可了解的 MIME type,能够用“,”做分隔符列出多个类型,让服务器有更多的选择地步,例如下面的这个头:

Accept: text/html,application/xml,image/webp,image/png

这便是告知服务器:“我能够看懂 HTML、XML 的文本,还有 webp 和 png 的图片,请给我这四类格局的数据”。

相应的,服务器会在呼应报文里用头字段Content-Type告知实体数据的真实类型:

Content-Type: text/html
Content-Type: image/png

这样浏览器看到报文里的类型是“text/html”就知道是 HTML 文件,会调用排版引擎渲染出页面,看到“image/png”就知道是一个 PNG 文件,就会在页面上显现出图像。

Accept-Encoding字段符号的是客户端支持的紧缩格局,例如上面说的 gzip、deflate 等,同样也能够用“,”列出多个,服务器能够选择其中一种来紧缩数据,实践运用的紧缩格局放在呼应头字段Content-Encoding里。

Accept-Encoding: gzip, deflate, br
Content-Encoding: gzip

不过这两个字段是能够省掉的,假如恳求报文里没有 Accept-Encoding 字段,就表明客户端不支持紧缩数据;假如呼应报文里没有 Content-Encoding 字段,就表明呼应数据没有被紧缩。

言语类型与编码

互联网遍布全球,不同国家的人运用了许多不同的言语,虽然都是 text/html,但怎么让浏览器显现出每个人都可了解可阅览的言语文字呢?

HTTP 又引入了两个概念:言语类型与字符集。

所谓的言语类型便是人类运用的自然言语,例如英语、汉语等,而这些自然言语可能还有下属的地区性方言,所以在需要清晰区别的时分也要运用type-subtype的方法,不过这里的格局与数据类型不同,分隔符不是“/”,而是“-”

举几个比方:en 表明恣意的英语,en-US 表明美式英语,en-GB 表明英式英语

关于自然言语的计算机处理还有一个更麻烦的东西叫做“字符集”。

在计算机发展的前期,各个国家和地区的人们“各自为政”,发明了许多字符编码方法来处理文字,比方英语国际用的 ASCII、汉语国际用的 GBK、BIG5等。同样的一段文字,用一种编码显现正常,换另一种编码后可能就会变得一团糟。

所以后来就出现了 Unicode 和 UTF-8,把国际上一切的言语都包容在一种编码方案里,UTF-8 也成为了互联网上的规范字符集。

言语类型运用的头字段

HTTP 协议也运用 Accept 恳求头字段和 Content 实体头字段,用于客户端和服务器就言语与编码进行“内容洽谈”。

Accept-Language字段符号了客户端可了解的自然言语,也允许用“,”做分隔符列出多个类型:

Accept-Language: zh-CN, zh, en

这个恳求头会告知服务器:“最好给我 zh-CN 的汉语文字,假如没有就用其他的汉语方言,假如还没有就给英文”。

相应的,服务器应该在呼应报文里用头字段Content-Language告知客户端实体数据运用的实践言语类型:

Content-Language: zh-CN

字符集在 HTTP 里运用的恳求头字段是Accept-Charset,但呼应头里却没有对应的 Content-Charset,而是在Content-Type字段的数据类型后边用“charset=xxx”来表明。

例如,浏览器恳求 GBK 或 UTF-8 的字符集,然后服务器回来的是 UTF-8 编码,便是下面这样:

Accept-Charset: gbk, utf-8
Content-Type: text/html; charset=utf-8

不过现在的浏览器都支持多种字符集,通常不会发送 Accept-Charset,而服务器也不会发送 Content-Language,由于运用的言语完全能够由字符集推断出来,所以在恳求头里一般只会有 Accept-Language 字段,呼应头里只会有 Content-Type 字段。

HTTP(13):Body的数据

内容洽谈的质量值

在 HTTP 协议里用 Accept、Accept-Encoding、Accept-Language 等恳求头字段进行内容洽谈的时分,还能够用一种特殊的“q”参数表明权重来设定优先级,这里的“q”是“quality factor”的意思。

权重的最大值是 1,最小值是 0.01,默认值是 1,假如值是 0 就表明回绝。具体的方法是在数据类型或言语代码后边加一个;,然后是q=value

例如下面的 Accept 字段:

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

它表明浏览器最期望运用的是 HTML 文件,权重是 1,其次是 XML 文件,权重是 0.9,最后是恣意数据类型,权重是 0.8。服务器收到恳求头后,就会计算权重,再依据自己的实践情况优先输出 HTML 或者 XML。

内容洽谈的成果

内容洽谈的过程是不透明的,每个 Web 服务器运用的算法都不相同。但有的时分,服务器会在呼应头里多加一个Vary字段,记录服务器在内容洽谈时参阅的恳求头字段,给出一点信息,例如:

Vary: Accept-Encoding,User-Agent,Accept

这个 Vary 字段表明服务器依据了 Accept-Encoding、User-Agent 和 Accept 这三个头字段,然后决议了发回的呼应报文。

Vary 字段能够认为是呼应报文的一个特殊的“版别符号”。每当 Accept 等恳求头改变时,Vary 也会随着呼应报文一同改变。也便是说,同一个 URI 可能会有多个不同的“版别”,首要用在传输链路中心的代理服务器完成缓存服务,这个之后讲“HTTP 缓存”时还会再说到。

小结

HTTP(13):Body的数据

  1. 数据类型表明实体数据的内容是什么,运用的是 MIME type,相关的头字段是 Accept 和 Content-Type;
  2. 数据编码表明实体数据的紧缩方法,相关的头字段是 Accept-Encoding 和 Content-Encoding;
  3. 言语类型表明实体数据的自然言语,相关的头字段是 Accept-Language 和 Content-Language;
  4. 字符集表明实体数据的编码方法,相关的头字段是 Accept-Charset 和 Content-Type;
  5. 客户端需要在恳求头里运用 Accept 等头字段与服务器进行“内容洽谈”,要求服务器回来最合适的数据;
  6. Accept 等头字段能够用“,”顺序列出多个可能的选项,还能够用“;q=”参数来精确指定权重。