HTTP的实体数据

前面我们以及了解到一个http报文是由header+body组成的,但那时我们主要研究的是header,没有涉及到body,

数据类型编码

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

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

你可以设想一下,假如http没有告知数据类型的功能,服务器把一大坨,数据发给了浏览器浏览器看到的是一个黑盒子,这时候该怎么办呢?

当然它可以猜因为很多数据都是有固定格式的,所以通过检查数据的前几个字节也许就能知道GIF图片,或者其他文件了,但这种方式无疑是十分低效的,而且有很大概率会检查不出文件类型

幸运的是,早在http协议诞生之前就已经有了针对这种问题的解决方案,不过它是用在电子邮件系统里的,让电子邮件可以发送ascll编码意外的任意数据,方案名字叫做:多用途互联网邮件扩展,简称为 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,即不透明的二进制数据。

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

比起 MIME type 来说,Encoding type 就少了很多,常用的只有下面三种:

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

数据类型使用的头字段

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

http协议为此定了两个Accept请求头字段和Content实体头字段,由于客户端和服务器进行内容协商,也就是说客户端用accept头告诉服务器希望介绍到什么样的数据,而服务器用content头告诉客户端实际发送了什么样的数据

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字段标记的是客户端支持的压缩格式,例如上面说的gzipdeflate等,同样也可以用 , 列出多个,服务器可以选择其中一种来压缩数据,实际使用的压缩格式放在 Content-Encoding

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

不过这两个字段是可以省略的,如果请求报文中没有 Accept-Encoding 字段,就表示客户端不支持压缩数据,如果响应报文里没有 Content-Encoding 字段,就表示响应数据没有被压缩

语言与编码

mime typeencoding type 解决了计算机理解 body 数据的问题,但互联网遍布全球,不同国家不同地区的人使用了很多不同的语言,虽然都是 text/html 但如何让浏览器显示出每个人都可以立即可阅读的语言文字呢

这实际上就是国际化问题,http采用了与数据类型相似的解决方案,又引入了两个概念,语言类型与字符集

所谓的语言类型就是人类使用的自然语言,例如英语,汉语,日语等,而这些自然语言可能还有下属的地区性方言,所以再需要明确区分的时候就要使用 type-subtype 的形式,不过这里的格式与数据类型不同,分隔符不是 / 而是 -

举个例子:en 表示任意的英语,en-us 表示美式英语,en-gb 表示英式英语,而zh-ch表示我们的汉语

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

在计算机发展的早期,各个国家和地区的人们 各自为政,发明了许多字符编码方式来处理文字,比如英语世界用 ascll ,汉语世界用 gbk,日语世界用 shift_jls等,同一段文字,用一种编码显示正常,换另一种编码后就会变得一团糟‘

所以后来出现了 unicodeutf-8,把世界上所有的语言都容纳在一种编码方案里,utf-8 也成为互联网上标准的字符集

语言类型使用的头字段

同样的 http 协议也使用 Accept 请求头字段和 Content 实体头字段,用于客户端和服务器就语言与编码进行内容协商

Accept-Languages 字段标记了客户端可理解的自然语言,也允许使用,做分隔符列出多个类型,例如

Accept-Language: zh-CH, 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 协议里用 Accept、Accept-Encoding、Accept-Language 等请求头字段进行内容协商的时候,还可以用一种特殊的“q”参数表示权重来设定优先级,这里的“q”是“quality factor”的意思。

权重的最大值是 1,最小值是 0.01,默认值是 1,如果值是 0 就表示拒绝。具体的形式是在数据类型或语言代码后面加一个“;”,然后是“q=value”。

这里要提醒的是“;”的用法,在大多数编程语言里“;”的断句语气要强于“,”,而在 HTTP 的内容协商里却恰好反了过来,“;”的意义是小于“,”的。

例如下面的 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 里的数据类型和语言类型,在这里为今天的内容做个小结。

  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=”参数来精确指定权重。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值