重新认识HTTP(四)
可以说,我们浏览网页,下载资源,甚至克隆一个感兴趣的github仓库,都在与HTTP协议打交道。但是,在计算机网络课程和考研中HTTP都不作为重点去讲述,而在面试和实际工作中却经常需要接触。因此更深入的了解HTTP协议显得尤为重要。这一部分重点介绍关于HTTP/1.1新增的内哦荣协商策略。
内容协商
概述
我们在抓包或者写爬虫时经常注意到有很多以Accept开头的请求首部,还有q=xxx之类的东西,这些个东西都是什么意思?
以Accept-Language为例,我们容易猜测到是用户浏览器向服务器请求的语言选项。一个URL常常需要代表若干不同的资源。例如那种需要以多种语言提供其内容的网站站点。如果某个站点有说中文的和说英语的两种用户,它可能想用这两种语言提供网站站点信息。理想情况下,服务器应当向英语用户发送英文版,向中文用户发送中文版——用户只要访问网站主页就可以得到相应语言的内容。
HTTP提供了内容协商方法,允许客户端和服务器作这样的决定。通过这些方法,单一的URL就可以代表不同的资源(比如,同一个网站页面的中文版和英语版),这些不同的版本称为变体。
方式
一共有3种不同的方法可以决定服务器上哪个页面最适合客户端:客户端来选择、服务器自动判定、让中间代理来选。这三种技术分别称为客户端驱动的协商、服务器驱动的协商以及透明协商。
客户端驱动
客户端发起请求,服务器发送返回一个页面,该页面包含指向该资源所有可用表示的链接,客户端作出选择后再发送第二次请求。
- 优点:比较自然,服务器提供内容,由客户进行选择,减少Header冗余
- 缺点:增加了时延,至少要发送两次请求,第一次请求获取资源列表,第二次获取选择的副本;同时HTTP 标准也没有明确指定提供可选资源链接的页面的格式,无法进行无感知的自动化选择。
服务器驱动
服务器检查客户端的请求首部集并决定提供哪个版本的页面。
- 优点:比客户端驱动的协商要快。HTTP提供了q机制,允许服务器近似匹配。
- 缺点:首部集不匹配,服务器要做猜测;
目前浏览器是采用服务器驱动的协商策略。当然服务器仍然可以在页面上提供语言选项供用户手动选择,就像大多数多语言的网页一样。
内容协商首部
客户端
客户端可以用下面列出的内容协商首部集发送用户的偏好信息:
Accept:告知服务器发送何种媒体类型; Accept-Language:告知服务器发送何种语言; Accept-Charset:告知服务器发送何种字符集; Accept-Encoding:告知服务器采用何种编码;
服务器
服务器用下面列出的实体首部集来匹配客户端的Accept首部集:
Accept首部 实体首部 Accept Content-Type Accept-Language Content-Language Accept-Charset Content-Type Accept-Encoding Content-Encoding
同时,实体首部也不是必须的。比如,如果没有 Content-Language ,则默认为内容适用于所有语言受众。
q值
这里的q是指Quality values。
q值的范围从0.0~1.0(1.0优先级最高)
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
这个首部表示:用户最愿意接受中文(zh),繁体的也行,英文次之。其他语言不接受(或以q=0.0表示)。如果是表示不特指的话是会以星号*表示。
vary
前面提到,客户端驱动是很自然的思路,也就是服务端提供,客户选择。实际广泛采用的情况是服务端驱动,也就是客户端提供多种接受的选项,服务器提供一个最符合的。
但是,服务端有时候只能提供一种内容,比如我就只有中文版的网页供用户查看。有而且,实际上大多数时候会存在中间缓存服务器来缓解内容提供服务器的压力。vary就主要用在这种情形下。
HTTP的vary响应首部中列出了所有客户端请求首部,缓存服务器可以用这些首部来选择文档或者产生定制的内容。比如:若给客户端的响应内容取决于Accept-Encoding,vary首部就必须包含Accept-Encoding。回到上面说的情况,既然只有中文版的网页,vary首部就不包含Accept-Language,这样缓存服务器就不用根据用户的Accept-Language来进行内容选择了,可以省很多工作。
相应的,为了实现透明协商,缓存服务器必须为每个已缓存变体保存客户端请求首部和相应的服务器响应首部。也就是指明vary的内容,就必须要缓存。
实例
以访问我自己的博客为例:
请求头(客户端):
响应头(服务器)
vary字段为Accept-Encoding。
更多
内容协商策略为改善互联网用户的体验,提高传输效率提供了很大的帮助。但是内容协商使HTTP头增大了不少,而且在每一次请求中都必须发送这些首部。在首部很少的时候,这并不是问题,但是随着数量的增多,消息体的体积会导致性能的下降。带有精确信息的首部发送的越多,信息熵就会越大,也就准许了更多 HTTP 指纹识别行为,以及与此相关的隐私问题的发生。另外,如果希望更详细的了解内容协商算法,可以参见Apache 服务器的内容协商算法。
总结
这一部分介绍了HTTP内容协商相关的内容。内容协商充分照顾了客户端的意愿,让服务端有机会展现自己更愿意被看到的一面。后面的内容将介绍HTTP2的知识。HTTP2的变化很多,值得我们去详细的去分析。