title: 图解http
date: 2022-06-09 22:24:25
tags:
- 计算机网络
- http
- tcp/ip
cover: /image/1.jpg
categories: - 计算机网络
第一章 .了解Web及网络基础
网络基础TCP/IP协议族:
日常使用的网络是在TCP/IP协议族的基础上运作的,http属于其内部的一个子集
计算机与网络需要相互建立通信,其中如何探测到通信目标,由哪一边发起通信,用哪种语言建立通信,怎样结束通信等等需要事先确定.我们把这些规则叫作协议
把互联网相关联的协议集合的总称叫作TCP/IP.
1.1TCP/IP的分层管理:
TCP/IP协议族按层次分可分为以下四层:
应用层,传输层,网络层以及数据链路层
1.应用层
应用层决定了向用户提供应用服务时通信的活动.
TCP/IP协议族预存了各类通用的应用服务.比如,FTP(File Transfer Protocol,文件传输协议)和DNS(Domain Name System,域名系统)服务就是其中两类.
http协议就位于该层.
2.传输层
传输层对上层应用层提供处于网络连接中的两台计算机之间的数据传输
在传输层有两个性质不同的协议:TCP(Transmission Control Protocol,传输控制协议)和UDP(User Data Protocol,用户数据报协议)
3.网络层
网络层用来处理在网络上流动的数据包.数据包是网络传输的最小数据单位.该层规定了通过什么传输路线到达对方计算机,并把数据包传送给对方.
4.数据链路层(网络接口层)
用来处理连接网络的硬件部分.包括控制操作系统,硬件的设备驱动,NIC(Network Interface Card,网络适配器即网卡),及光纤等物理可见部分.
1.2TCP/IP通信传输流
HTTP 举例来说明,
- 首先作为发送端的客户端在应用层(HTTP 协议)发出一个想看某个 Web 页面的 HTTP 请求。
- 接着,为了传输方便,在传输层(TCP 协议)把从应用层处收到的数据(HTTP 请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。
- 在网络层(IP 协议),增加作为通信目的地的 MAC 地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。
- 接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的 HTTP请求。
1.3与HTTP密切相关的协议:IP,TCP和DNS
1.IP(Internet Protocol)网际协议
ip协议位于网络层,ip协议的作用是把各种数据包传送给对方,其中需要用到的重要条件是IP地址与MAC地址(Media Access Control Address).
Ip地址指明了节点被分配到的地址,MAC地址是指网卡所属的固定地址.IP地址可以变换,而MAC基本上不会改变.IP地址也可以和MAC地址进行配对.
使用ARP协议凭借MAC地址进行通信
IP间的通信依赖MAC地址。在网络上,通信的双发在同一局域网(LAN)内的情况是很少的,通常是经过台计算机和网络设备中转才能连接到对方。而在进行中转时,会利用下一站中转设备的MAC地址来搜索下一个中转目标。这是,会采用ARP协议(Address Resolution Protocol)。ARP是一种用以解析地址的协议,根据通信方的IP地址就可以反查出对应的MAC地址。
2.TCP协议
按层次分,TCP位于传输层,提供可靠的字节流服务。
所谓的字节流服务(Byte Stream Service)是指,为了方便传输,将大块数据分割成以报文段(segment)为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠的传送给对方。
为确保能到达目标
为了准确无误的将数据送达目标处,TCP协议采用了三次握手(three-way handshaking)策略。用TCP协议把数据包送出去后,TCP不会对传送后的情况置之不理,它一定会向对方确认是否成功送达。握手过程中使用了TCP的标志(flag)–SYN(synchronize)和ACK(acknowledgement).
发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以传达确认信息。最后,发送端再回传一个带ACK标志的数据包,代表“握手”结束。
若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。
3.负责域名解析的DNS服务
DNS(Domain Name System)服务是和HTTP协议一样位于应用层的协议。它提供域名到IP地址之间的解析服务。
计算机既可以被赋予IP地址,也可以被赋予主机名和域名。比如www.baidu.com
DNS协议通过提供域名查找IP地址,或逆向从IP地址反查域名的服务。
1.4各种协议之间的关系
1.5URL与URI
URI(Uniform Resource Identifier):统一资源标识符;URL(Uniform Resource Locator):统一资源定位符。
URI用字符串标识某一互联网资源,而URL标识资源在互联网上的位置.
URI格式:
绝对 URI 的格式:
登录信息,服务器端口号,查询字符串与片段标识符均是可选项,方案协议名不区分大小写
第二章.简单的http协议
应用http协议时,在一条通信线路上必然是一方担任服务端,一方担任客户端.因此.http协议与tcp/ip协议族内的众多其他协议相同,用于客户端到服务器端之间的通信.
http协议规定,请求从客户端发出最后服务器端响应该请求并返回.
2.1请求报文
请求报文是由请求方法、请求 URI、协议版本、可选的请求首部字段和内容实体构成的。
2.2响应报文
响应报文基本上由协议版本、状态码(表示请求成功或失败的数字代码)、用以解释状态码的原因短语、可选的响应首部字段以及实体主体构成。
2.3http是不保存状态的协议
http自身不对请求和响应之间的通信状态进行保存,也就是说在http这个级别,协议对于发送过的请求和响应都不做持久化处理.因此在使用http协议时,每当有请求发送就会有新的响应产生.
2.4告知服务器意图的 HTTP 方法
方法 | 说明 | 支持的http协议版本 |
---|---|---|
GET | 获取资源 | 1.0,1.1 |
POST | 传输实体主体 | 1.0,1.1 |
PUT | 传输文件 | 1.0,1.1 |
HEAD | 获得报文首部 | 1.0,1.1 |
DELETE | 删除文件 | 1.0,1.1 |
OPTIONS | 询问支持的方法 | 1.1 |
TRACE | 追踪路径 | 1.1 |
CONNECT | 要求用隧道协议连接代理 | 1.1 |
LINK | 建立和资源之间的联系 | 1.0 |
UNLINE | 断开连接关系 | 1.0 |
LINK与UNLINE在http/1.1中已经被废弃
2.5持久连接
为了解决每次http请求与响应都要建立和断开TCP连接所带来的的额外的开销,http/1.1和部分http/1.0想出了持久连接方法(HTTP Persistent Connections,也称为 HTTP keep-alive或HTTP connection reuse),其特点是只要任意一方没有明确提出断开连接,则保持tcp连接状态.
2.6管线化
持久连接使得多数请求以**管线化(pipelining)**方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,不用等待响应亦可直接发送下一个请求。这样就能够做到同时并行发送多个请求,而不需要一个接一个地等待响应了。
比如,当请求一个包含10张图片的HTML Web页面,与挨个连接相比,用持久连接可以让请求更快结束。而管线化技术则比持久连接还要快。请求数越多,时间差就越明显。
2.7使用Cookie的状态管理
HTTP是无状态协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。假设要求登录认证的Web页面本身无法进行状态的管理(不记录已登录的状态),那么每次跳转新页面就要再次登录,或者要在每次请求报文中附加参数来管理登录状态。
不可否认,无状态协议当然也有它的优点。由于不必保存状态,自然可减少服务器的CPU及内存资源的消耗。从另一侧面来说,也正是因为HTTP协议本身是非常简单的,所以才会被应用在各种场景里。
保留无状态协议这个特征的同时又要解决类似的矛盾问题,于是引入了Cookie技术。Cookie技术通过在请求和响应报文中写入Cookie信息来控制客户端的状态。
Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去。
服务器端发现客户端发送过来的Cookie后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
没有Cookie信息状态下的请求
第2次以后(存有Cookie信息状态)的请求
①请求报文(没有Cookie信息的状态)
GET /reader/ HTTP/1.1
Host:hackr.jp
*首部字段内没有Cookie的相关信息
②响应报文(服务器端生成Cookie信息)
HTTP/1.1 200 OK
Date: Thu, 12 Jul 2012 07:12:20 GMT
Server: Apache
<Set-Cookie: sid=1342077140226724; path=/; expires=Wed, 10-Oct-12 07:12:20 GMT>
Content-Type: text/plain; charset=UTP-8
GET /image/ HTTP/1.1
Host:hackr.jp
Cookie: 1342077140226724
第三章.HTTP报文内的信息
3.1HTTP报文
用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP报文本身是由多行(用CR+LF作换行符)数据构成的字符串文本。
HTTP报文大致可分为报文首部和报文主体两块。两者由最初出现的空行(CR+LF,CR carriage return 回车符,0x0d,LF line Feed,换行符,0x0a)来划分。通常,并不一定要有报文主体。
HTTP报文的结构
3.2请求报文及响应报文的结构
1.请求报文与响应报文的结构
2.实例(上为请求报文,下为响应报文)
请求行:包含用于请求的方法,请求URI和HTTP版本。
状态行:包含表明响应结果的状态码,原因短语和HTTP版本。
首部字段:包含表示请求和响应的各种条件和属性的各类首部。一般有4种首部,分别是:通用首部、请求首部、响应首部和实体首部。
其他:可能包含HTTP的RFC里未定义的首部(Cookie等)。
3.3编码提升传输速率
HTTP在传输数据时可以按照数据原貌直接传输,但也可以在传输过程中通过编码提升传输速率。通过在传输时编码,能有效地处理大量的访问请求。但是,编码的操作需要计算机来完成,因此会消耗更多的CPU等资源。
3.4报文主题和实体主体之间的差异
报文(message):是HTTP通信中的基本单位,由8位组字节流(octet sequence,其中octet为8个比特)组成,通过HTTP通信传输。
实体(entity):作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。
HTTP报文的主体用于传输请求或响应的实体主体。通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。报文和实体这两个术语在之后会经常出现,请事先理解两者的差异。
3.5压缩传输的内容编码
向待发送邮件内增加附件时,为了使邮件容量变小,我们会先用ZIP压缩文件之后再添加附件发送。HTTP协议中有一种被称为内容编码的功能也能进行类似的操作。内容编码指明应用在实体内容上的编码格式,并保持实体信息原样压缩。内容编码后的实体由客户端接收并负责解码。
常用的内容编码有以下几种:gzip(GNU zip)、compress(UNIX系统的标准压缩)、deflate(zlib)、identity(不进行编码)
3.6分割发送的分块传输编码
在HTTP通信过程中,请求的编码实体资源尚未全部传输完成之前,浏览器无法显示请求页面。在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。这种把实体主体分块的功能称为分块传输编码(Chunked Transfer Coding)。
分块传输编码会将实体主体分成多个部分(块)。每一块都会用十六进制来标记块的大小,而实体主体的最后一块会使用**“0(CR+LF)”**来标记。使用分块传输编码的实体主体会由接收的客户端负责解码,恢复到编码前的实体主体。HTTP/1.1中存在一种称为传输编码(Transfer Coding)的机制,它可以在通信时按某种编码方式传输,但只定义作用于分块传输编码中。
3.7发送多种数据的多部分对象集合
发送邮件时,我们可以在邮件里写入文字并添加多份附件。这是因为采用了MIME(Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)机制,它允许邮件处理文本、图片、视频等多个不同类型的数据。例如,图片等二进制数据以ASCII码字符串编码的方式指明,就是利用MIME来描述标记数据类型。而在MIME扩展中会使用一种称为多部分对象集合(Multipart)的方法,来容纳多份不同类型的数据。
相应地,HTTP协议中也采纳了多部分对象集合,发送的一份报文主体内可含有多类型实体。通常是在图片或文本文件等上传时使用。
多部分对象集合包含的对象:
multipart/form-data:在Web表单文件上传时使用。
multipart/byteranges:状态码206(Partial Content,部分内容)响应报文包含了多个范围的内容时使用。
在HTTP报文中使用多部分对象集合时,需要在首部字段里加上Content-type。
使用boundary字符串来划分多部分对象集合指明的各类实体。在boundary字符串指定的各个实体的起始行之前插入“–”标记(例如:–AaB03x、–THIS_STRING_SEPARATES),而在多部分对象集合对应的字符串的最后插入“–”标记(例如:–AaB03x–、–THIS_STRING_SEPARATES–)作为结束。
多部分对象集合的每个部分类型中,都可以含有首部字段。另外,可以在某个部分中嵌套使用多部分对象集合。有关多部分对象集合更详细的解释,请参考RFC2046。
3.8获取部分内容的范围请求
以前,用户不能使用现在这种高速的带宽访问互联网,当时,下载一个尺寸稍大的图片或文件就已经很吃力了。如果下载过程中遇到网络中断的情况,那就必须重头开始。为了解决上述问题,需要一种可恢复的机制。所谓恢复是指能从之前下载中断处恢复下载。
要实现该功能需要指定下载的实体范围。像这样,指定范围发送的请求叫做范围请求(Range Request)。对一份10000字节大小的资源,如果使用范围请求,可以只请求5001~10000字节内的资源。
# 5001~10000字节
Range: bytes=5001-10000
# 从5001字节之后全部的
Range: bytes=5001-
# 从一开始到3000字节和5000~7000字节的多重范围
Range: bytes=-3000, 5000-7000
针对范围请求,响应会返回状态码为206 Partial Content的响应报文。另外,对于多重范围的范围请求,响应会在首部字段Content-Type标明multipart/byteranges后返回响应报文。
如果服务器端无法响应范围请求,则会返回状态码200 OK和完整的实体内容
3.9内容协商返回最合适的内容
当浏览器的默认语言为英语或中文,访问相同URI的Web页面时,则会显示对应的英语版或中文版的Web页面。这样的机制称为内容协商(ContentNegotiation)。
内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。
包含在请求报文中的某些首部字段(如下)就是判断的基准(Accept、Accept-Charset、Accept-Encoding、Accept-Language、Content-Language)。
内容协商技术有以下3种类型:
**服务器驱动协商(**Server-driven Negotiation):由服务器端进行内容协商。以请求的首部字段为参考,在服务器端自动处理。但对用户来说,以浏览器发送的信息作为判定的依据,并不一定能筛选出最优内容。
客户端驱动协商(Agent-driven Negotiation):由客户端进行内容协商的方式。用户从浏览器显示的可选项列表中手动选择。还可以利用JavaScript脚本在Web页面上自动进行上述选择。比如按OS的类型或浏览器类型,自行切换成PC版页面或手机版页面。
透明协商(Transparent Negotiation):是服务器驱动和客户端驱动的结合体,是由服务器端和客户端各自进行内容协商的一种方法。
第四章 .返回结果的HTTP状态码
4.1状态码告知从服务器端返回的请求结果
状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。
状态码如200 OK,以3位数字和原因短语组成。数字中的第一位指定了响应类别,后两位无分类。响应类别有以下5种。
4.2 2XX成功
200 OK
表示从客户端发来的请求在服务器端被正常处理了。在响应报文内,随状态码一起返回的信息会因方法的不同而发生改变。比如,使用GET方法时,对应请求资源的实体会作为响应返回;而使用HEAD方法时,对应请求资源的实体主体不随报文首部作为响应返回(即在响应中只返回首部,不会返回实体的主体部分)。
204 No Content
该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。比如,当从浏览器发出请求处理后,返回204响应,那么浏览器显示的页面不发生更新。一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。
206 Partial Content
该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求。响应报文中包含由Content-Range指定范围的实体内容。
4.3 3XX重定向
3XX响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。
301 Moved Permanently
永久性重定向。该状态码表示请求的资源已被分配了新的URI,以后应使用资源现在所指的URI。也就是说,如果已经把资源对应的URI保存为书签了,这时应该按Location首部字段提示的URI重新保存。像下方给出的请求URI,当指定资源路径的最后忘记添加斜杠“/”,就会产生301状态码。(http://example.com/sample)
302 Found
临时性重定向。该状态码表示请求的资源已被分配了新的URI,希望用户(本次)能使用新的URI访问。和301 Moved Permanently状态码相似,但302状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的URI将来还有可能发生改变。比如,用户把URI保存成书签,但不会像301状态码出现时那样去更新书签,而是仍旧保留返回302状态码的页面对应的URI。
303 See Other
该状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源。303状态码和302 Found状态码有着相同的功能,但303状态码明确表示客户端应当采用GET方法获取资源,这点与302状态码有区别。
比如,当使用POST方法访问CGI程序,其执行后的处理结果是希望客户端能以GET方法重定向到另一个URI上去时,返回303状态码。虽然302 Found状态码也可以实现相同的功能,但这里使用303状态码是最理想的。
Tips: 当301、302、303响应状态码返回时,几乎所有的浏览器都会把POST改成GET,并删除请求报文内的主体,之后请求会自动再次发送。301、302标准是禁止将POST方法改变成GET方法的,但实际使用时大家都会这么做。
304 Not Modified
该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304 Not Modified(服务器端资源未改变,可直接使用客户端未过期的缓存)。304状态码返回时,不包含任何响应的主体部分。304虽然被划分在3XX类别中,但是和重定向没有关系。
307 Temporary Redirect
临时重定向。该状态码与302 Found有着相同的含义。尽管302标准禁止POST变换成GET,但实际使用时大家并不遵守。
307会遵照浏览器标准,不会从POST变成GET。但是,对于处理响应时的行为,每种浏览器有可能出现不同的情况。
4.4 4XX客户端错误
4XX的响应结果表明客户端是发生错误的原因所在。
400 Bad Request
该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像200 OK一样对待该状态码。
401 Unauthorized
该状态码表示发送的请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息。另外若之前已进行过1次请求,则表示用户认证失败。返回含有401的响应必须包含一个适用于被请求资源的WWW-Authenticate首部用以质询(challenge)用户信息。当浏览器初次接收到401响应,会弹出认证用的对话窗口。
403 Forbidden
该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。
未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源IP地址试图访问)等列举的情况都可能是发生403的原因。
404 Not Found
该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。
4.5 5XX服务器错误
5XX的响应结果表明服务器本身发生错误。
500 Internal Server Error
该状态码表明服务器端在执行请求时发生了错误。也有可能是Web应用存在的bug或某些临时的故障。
503 Service Unavailable
该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入Retry-After首部字段再返回给客户端。
状态码和状况的不一致:不少返回的状态码响应都是错误的,但是用户可能察觉不到这点。比如Web应用程序内部发生错误,状态码依然返回200 OK,这种情况也经常遇到。
第五章. 与http协作的WEB服务器
5.1 用单台虚拟主机模拟多个域名
http/1.1 规范允许一台http服务器搭建多个Web站点.这是因为利用了虚拟主机(VirtualHost,又称虚拟服务器)的功能。
在互联网上,域名通过DNS服务器映射到IP地址之后访问目标网站.
可见,当请求发送到服务器时,已经是以IP地址形式访问了。
所以,如果一台服务器内托管了www.tricorder.jp和www.hackr.jp这两个域名,当收到请求时就需要弄清楚究竟要访问哪个域名。
在相同的IP地址下,由于虚拟主机可以寄存多个不同主机名和域名的Web网站,因此在发送HTTP请求时,必须在Host首部内完整指定主机名或域名的URI。
5.2 通信数据转发程序: 代理,网关,隧道
- 代理:代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“中间人”的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。
- 网关:网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个网关。
- 隧道:隧道是在相隔甚远的客户端和服务器两者之间进行中转,并保持双方通信连接的应用程序。
1.代理
代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求URI,会直接发送给前方持有资源的目标服务器。持有资源实体的服务器被称为源服务器。从源服务器返回的响应经过代理服务器后再传给客户端。
每次通过代理服务器转发请求或响应时,会追加写入Via首部信息
使用代理服务器的理由有:利用缓存技术(稍后讲解)减少网络带宽的流量,组织内部针对特定网站的访问控制,以获取访问日志为主要目的,等等。代理有多种使用方法,按两种基准分类。一种是是否使用缓存,另一种是是否会修改报文。
- 缓存代理:代理转发响应时,缓存代理(Caching Proxy)会预先将资源的副本(缓存)保存在代理服务器上。当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。
- 透明代理:转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理(Transparent Proxy)。反之,对报文内容进行加工的代理被称为非透明代理。
2.网关
网关的工作机制和代理十分相似。而网关能使通信线路上的服务器提供非HTTP协议服务。
**利用网关能提高通信的安全性,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。**比如,网关可以连接数据库,使用SQL语句查询数据。另外,在Web购物网站上进行信用卡结算时,网关可以和信用卡结算系统联动。
3.隧道
隧道可按要求建立起一条与其他服务器的通信线路,届时使用SSL等加密手段进行通信。隧道的目的是**确保客户端能与服务器进行安全的通信。**隧道本身不会去解析HTTP请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束。
通过隧道的传输,可以和远距离的服务器安全通信。隧道本身是透明的,客户端不用在意隧道的存在。
5.3保存资源的缓存
缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。
5.3.1缓存的有效期限
即便缓存服务器内有缓存,也不能保证每次都会返回对同资源的请求。因为这关系到被缓存资源的有效性问题。当遇上源服务器上的资源更新时,如果还是使用不变的缓存,那就会演变成返回更新前的“旧”资源了。即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效,缓存服务器将会再次从源服务器上获取“新”资源。
5.3.2 客户端的缓存
缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以InternetExplorer程序为例,把客户端缓存称为**临时网络文件(Temporary InternetFile)。**浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。另外,和缓存服务器相同的一点是,当判定缓存过期后,会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。
Tips:在HTTP出现之前的协议
**FTP(File Transfer Protocol):**传输文件时使用的协议。该协议历史久远,可追溯到1973年前后,比TCP/IP协议族的出现还要早。虽然它在1995年被HTTP的流量(Traffic)超越,但时至今日,仍被广泛沿用。
**NNTP(Network News Transfer Protocol):**用于NetNews电子会议室内传送消息的协议。在1986年前后出现,属于比较古老的一类协议。现在,利用Web交换信息已成主流,所以该协议已经不怎么使用了。
**Archie:**搜索anonymous FTP公开的文件信息的协议。1990年前后出现,现在已经不常使用。
**WAIS(Wide Area Information Servers):**以关键词检索多个数据库使用的协议。1991年前后出现。由于现在已经被HTTP协议替代,也已经不怎么使用了。
**Gophe:**查找与互联网连接的计算机内信息的协议。1991年前后出现,由于现在已经被HTTP协议替代,也已经不怎么使用了。
第六章. http首部
6.1 HTTP报文首部
HTTP协议的请求和响应报文中必定包含HTTP首部。首部内容为客户端和服务器分别处理请求和响应提供所需要的信息。对于客户端用户来说,这些信息中的大部分内容都无须亲自查看。
HTTP请求报文:在请求中,HTTP报文由方法、URI、HTTP版本、HTTP首部字段等部分构成。
下面的示例是访问http://hackr.jp时,请求报文的首部信息。
HTTP响应报文:在响应中,HTTP报文由HTTP版本、状态码(数字和原因短语)、HTTP首部字段3部分构成。
以下示例是之前请求访问http://hackr.jp/时,返回的响应报文的首部信息。
在报文众多的字段当中,HTTP首部字段包含的信息最为丰富。首部字段同时存在于请求和响应报文内,并涵盖HTTP报文相关的内容信息。因HTTP版本或扩展规范的变化,首部字段可支持的字段内容略有不同。本书主要涉及HTTP/1.1及常用的首部字段。
6.2 HTTP首部字段
6.2.1 HTTP首部字段传递重要信息
HTTP首部字段是构成HTTP报文的要素之一。在客户端与服务器之间以HTTP协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外重要信息的作用。
使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。
6.2.2 HTTP首部字段结构
HTTP首部字段是由首部字段名和字段值构成的,**中间用冒号“:”分隔。**例如,在HTTP首部中以Content-Type这个字段来表示报文主体的对象类型。首部字段名为Content-Type,字符串text/html是字段值。字段值对应单个HTTP首部字段可以有多个值。
Content-Type: text/html
Keep-Alive: timeout=15, max=100
Tips:若HTTP首部字段重复了会如何
当HTTP报文首部中出现了两个或两个以上具有相同首部字段名时会怎么样?这种情况在规范内尚未明确,根据浏览器内部处理逻辑的不同,结果可能并不一致。有些浏览器会优先处理第一次出现的首部字段,而有些则会优先处理最后出现的首部字段。
6.2.3 4种HTTP首部字段类型
-
通用首部字段(General Header Fields):请求报文和响应报文两方都会使用的首部。
-
请求首部字段(Request Header Fields):从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
-
响应首部字段(Response Header Fields):从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
-
实体首部字段(Entity Header Fields):针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
6.2.4 HTTP/1.1 首部字段一览
HTTP/1.1规范定义了如下47种首部字段。
通用首部字段(General Header Fields)
请求首部字段(Request Header Fields)
响应首部字段(Response Header Fields
实体首部字段(Entity Header Fields
6.2.5 非HTTP/1.1首部字段
在HTTP协议通信交互中使用到的首部字段,不限于RFC2616中定义的47种首部字段。还有Cookie、Set-Cookie和Content-Disposition等在其他RFC中定义的首部字段,它们的使用频率也很高。这些非正式的首部字段统一归纳在RFC4229 HTTP Header Field Registrations中。
6.2.6 End-to-end首部和Hop-by-hop首部
HTTP首部字段将定义成缓存代理和非缓存代理的行为,分成2种类型。
-
端到端首部(End-to-end Header):分在此类别中的首部会转发给请求/响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
-
逐跳首部(Hop-by-hop Header):分在此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。HTTP/1.1和之后版本中,如果要使用hop-by-hop首部,需提供Connection首部字段。
下面列举了HTTP/1.1中的逐跳首部字段。除这8个首部字段之外,其他所有字段都属于端到端首部。Connection、Keep-Alive、Proxy-Authenticate、Proxy-Authorization、Trailer、TE、Transfer-Encoding、Upgrade。
6.3 HTTP/1.1 通用首部字段
通用首部字段是指,请求报文和响应报文双方都会使用的首部。
6.3.1 Cache-Control
通过指定首部字段Cache-Control的指令,就能操作缓存的工作机制。
指令的参数是可选的,多个指令之间通过“,”分隔。首部字段Cache-Control的指令可用于请求及响应时。
Cache-Control: private, max-age=0, no-cache
Cache-Control指令,缓存请求指令
Cache-Control指令,缓存响应指令
表示是否能缓存的指令:
Cache-Control: public
Cache-Control: private
Cache-Control: no-cache
Cache-Control: no-cache=Location
-
public指令:当指定使用public指令时,则明确表明其他用户也可利用缓存。
-
private指令:当指定private指令后,响应只以特定的用户作为对象,这与public指令的行为相反。缓存服务器会对该特定用户提供资源缓存的服务,对于其他用户发送过来的请求,代理服务器则不会返回缓存。
-
no-cache指令:使用no-cache指令的目的是为了防止从缓存中返回过期的资源。客户端发送的请求中如果包含no-cache指令,则表示客户端将不会接收缓存过的响应。于是,“中间”的缓存服务器必须把客户端请求转发给源服务器。如果服务器返回的响应中包含no-cache指令,那么缓存服务器不能对资源进行缓存。源服务器以后也将不再对缓存服务器请求中提出的资源有效性进行确认,且禁止其对响应资源进行缓存操作。由服务器返回的响应中,若报文首部字段Cache-Control中对no-cache字段名具体指定参数值,那么客户端在接收到这个被指定参数值的首部字段对应的响应报文后,就不能使用缓存。换言之,无参数值的首部字段可以使用缓存。只能在响应指令中指定该参数。
控制可执行缓存的对象的指令.
-
no-store指令:当使用no-store指令时,暗示请求(和对应的响应)或响应中包含机密信息。因此,该指令规定缓存不能在本地存储请求或响应的任一部分。
Cache-Control: no-store
指定缓存期限和认证的指令
- s-maxage指令:s-maxage指令的功能和max-age指令的相同,它们的不同点是s-maxage指令只适用于供多位用户使用的公共缓存服务器。也就是说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。另外,当使用s-maxage指令后,则直接忽略对Expires首部字段及max-age指令的处理。
Cache-Control: s-maxage=604800 // 单位秒
- max-age指令
Cache-Control: max-age=604800 // 单位秒
当客户端发送的请求中包含max-age指令时,如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源。另外,当指定max-age值为0,那么缓存服务器通常需要将请求转发给源服务器。当服务器返回的响应中包含max-age指令时,缓存服务器将不对资源的有效性再作确认,而max-age数值代表资源保存为缓存的最长时间。应用HTTP/1.1版本的缓存服务器遇到同时存在Expires首部字段的情况时,会优先处理max-age指令,而忽略掉Expires首部字段。而HTTP/1.0版本的缓存服务器的情况却相反,max-age指令会被忽略掉。
- min-fresh指令
Cache-Control: min-fresh=60 // 单位秒
min-fresh指令要求缓存服务器返回至少还未过指定时间的缓存资源。比如,当指定min-fresh为60秒后,在这60秒以内如果有超过有效期限的资源都无法作为响应返回了。
- max-stale指令
Cache-Control: max-stale=3600 // 单位秒
使用max-stale可指示缓存资源,即使过期也照常接收。如果指令未指定参数值,那么无论经过多久,客户端都会接收响应;如果指令中指定了具体数值,那么即使过期,只要仍处于max-stale指定的时间内,仍旧会被客户端接收。
- only-if-cached指令
Cache-Control: only-if-cached
使用only-if-cached指令表示客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回。换言之,该指令要求缓存服务器不重新加载响应,也不会再次确认资源有效性。若发生请求缓存服务器的本地缓存无响应,则返回状态码504Gateway Timeout。
- must-revalidate指令
Cache-Control: must-revalidate
使用must-revalidate指令,代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。若代理无法连通源服务器再次获取有效资源的话,缓存必须给客户端一条504(Gateway Timeout)状态码。另外,使用must-revalidate指令会忽略请求的max-stale指令(即使已经在首部使用了max-stale,也不会再有效果)。
- proxy-revalidate指令
Cache-Control: proxy-revalidate
proxy-revalidate指令要求所有的缓存服务器在接收到客户端带有该指令的请求返回响应之前,必须再次验证缓存的有效性。
- no-transform指令
Cache-Control: no-transform
使用no-transform指令规定无论是在请求还是响应中,缓存都不能改变实体主体的媒体类型。这样做可防止缓存或代理压缩图片等类似操作。
Cache-Control扩展
- cache-extension token
Cache-Control: private, community="UCI"
通过cache-extension标记(token),可以扩展Cache-Control首部字段内的指令。如上例,Cache-Control首部字段本身没有community这个指令。借助extension tokens实现了该指令的添加。如果缓存服务器不能理解community这个新指令,就会直接忽略。因此,extension tokens仅对能理解它的缓存服务器来说是有意义的。
6.3.2 Connection
Connection首部字段具备如下两个作用。(控制不再转发给代理的首部字段、管理持久连接)
控制不再转发给代理的首部字段
Connection: 不在转发的首部字段名
在客户端发送请求和服务器返回响应内,使用Connection首部字段,可控制不再转发给代理的首部字段(即Hop-by-hop首部)。
管理持久连接
Connection: close
HTTP/1.1版本的默认连接都是持久连接。为此,客户端会在持久连接上连续发送请求。当服务器端想明确断开连接时,则指定Connection首部字段的值为Close。
Connection: Keep-Alive
HTTP/1.1之前的HTTP版本的默认连接都是非持久连接。为此,如果想在旧版本的HTTP协议上维持持续连接,则需要指定Connection首部字段的值为Keep-Alive。
如上图①所示,客户端发送请求给服务器时,服务器端会像上图②那样加上首部字段Keep-Alive及首部字段Connection后返回响应。
6.3.3 Date
首部字段Date表明创建HTTP报文的日期和时间。
HTTP/1.1协议使用在RFC1123中规定的日期时间的格式,如下示例。
Date:Tue, 03 Jul 2012 04:40:59 GMT
Date:Tue, 03-Jul-12 04:40:59 GMT
除此之外,还有一种格式。它与C标准库内的asctime()函数的输出格式一致。
Date:Tue Jul 03 04:40:59 2012
6.3.4 Pragma
Pragma是HTTP/1.1之前版本的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义。
Pragma: no-cache
该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源。
所有的中间服务器如果都能以HTTP/1.1为基准,那直接采用Cache-Control: no-cache指定缓存的处理方式是最为理想的。但要整体掌握全部中间服务器使用的HTTP协议版本却是不现实的。因此,发送的请求会同时含有下面两个首部字段。
Cache-Control: no-cache
Pragma: no-cache
6.3.5 Trailer
首部字段Trailer会事先说明在报文主体后记录了哪些首部字段。该首部字段可应用在HTTP/1.1版本分块传输编码时。
以上用例中,指定首部字段Trailer的值为Expires,在报文主体之后(分块长度0之后)出现了首部字段Expires。
6.3.6 Transfer-Encoding
首部字段Transfer-Encoding规定了传输报文主体时采用的编码方式。
HTTP/1.1的传输编码方式仅对分块传输编码有效。
以上用例中,正如在首部字段Transfer-Encoding中指定的那样,有效使用分块传输编码,且分别被分成3312字节和914字节大小的分块数据。
6.3.7 Upgrade
首部字段Upgrade用于检测HTTP协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。
上图用例中,首部字段Upgrade指定的值为TLS/1.0。请注意此处两个字段首部字段的对应关系,Connection的值被指定为Upgrade。U**pgrade首部字段产生作用的Upgrade对象仅限于客户端和邻接服务器之间。**因此,使用首部字段Upgrade时,还需要额外指定Connection:Upgrade。
对于附有首部字段Upgrade的请求,服务器可用101 Switching Protocols状态码作为响应返回。
6.3.8 Via
使用首部字段Via是为了追踪客户端与服务器之间的请求和响应报文的传输路径。**报文经过代理或网关时,会先在首部字段Via中附加该服务器的信息,然后再进行转发。**这个做法和traceroute及电子邮件的Received首部的工作机制很类似。首部字段Via不仅用于追踪报文的转发,还可避免请求回环的发生。所以必须在经过代理时附加该首部字段内容。
上图用例中,在经过代理服务器A时,Via首部附加了“1.0 gw. hackr.jp(Squid/3.1)”这样的字符串值。行头的1.0是指接收请求的服务器上应用的HTTP协议版本。接下来经过代理服务器B时亦是如此,在Via首部附加服务器信息,也可增加1个新的Via首部写入服务器信息。
Via首部是为了追踪传输路径,所以经常会和TRACE方法一起使用。比如,代理服务器接收到由TRACE方法发送过来的请求(其中Max-Forwards: 0)时,代理服务器就不能再转发该请求了。这种情况下,代理服务器会将自身的信息附加到Via首部后,返回该请求的响应。
6.3.9 Warning
HTTP/1.1的Warning首部是从HTTP/1.0的响应首部(Retry-After)演变过来的。该首部通常会告知用户一些与缓存相关的问题的警告。
Warning首部的格式如下。最后的日期时间部分可省略。
HTTP/1.1中定义了7种警告。警告码对应的警告内容仅推荐参考。另外,警告码具备扩展性,今后有可能追加新的警告码。
6.4 请求首部字段
请求首部字段是从客户端往服务器端发送请求报文中所使用的字段,用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等内容。
6.4.1 Accept
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept首部字段可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。可使用type/subtype这种形式,一次指定多种媒体类型。下面我们试举几个媒体类型的例子。
下面我们试举几个媒体类型的例子。
- 文本文件:text/html、text/plain、text/css、application/xhtml+xml、application/xml …
- 图片文件:image/jpeg、image/gif、image/png …
- 视频文件:video/mpeg、video/quicktime …
- 应用程序使用的二进制文件:application/octet-stream, application/zip …
比如,如果浏览器不支持PNG图片的显示,那Accept就不指定image/png,而指定可处理的image/gif和image/jpeg等图片类型。
若想要给显示的媒体类型增加优先级,则使用q=来额外表示权重值,用分号(;)进行分隔。权重值q的范围是0~1(可精确到小数点后3位),且1为最大值。不指定权重q值时,默认权重为q=1.0。当服务器提供多种内容时,将会首先返回权重值最高的媒体类型。
6.4.2 Accept-Charset
Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
Accept-Charset首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。另外,可一次性指定多种字符集。与首部字段Accept相同的是可用权重q值来表示相对优先级。该首部字段应用于内容协商机制的服务器驱动协商。
6.4.3 Accept-Encoding
Accept-Encoding: gzip, deflate
Accept-Encoding首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码。采用权重q值来表示相对优先级,这点与首部字段Accept相同。另外,也可使用星号(*)作为通配符,指定任意的编码格式。
下面试举出几个内容编码的例子。
- gzip:由文件压缩程序gzip(GNU zip)生成的编码格式(RFC1952),采用Lempel-Ziv算法(LZ77)及32位循环冗余校验(Cyclic RedundancyCheck,通称CRC)。
- compress:由UNIX文件压缩程序compress生成的编码格式,采用Lempel-Ziv-Welch算法(LZW)。
- deflate:组合使用zlib格式(RFC1950)及由deflate压缩算法(RFC1951)生成的编码格式。
- identity:不执行压缩或不会变化的默认编码格式
6.4.4 Accept-Language
Accept-Language: zh-cn, zh;q=0.7,en-us,en;q=0.3
首部字段Accept-Language用来告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级。可一次指定多种自然语言集。和Accept首部字段一样,按权重值q来表示相对优先级。在上述图例中,客户端在服务器有中文版资源的情况下,会请求其返回中文版对应的响应,没有中文版时,则请求返回英文版响应。
6.4.5 Authorization
Authorization: Basic dWVub3N1bjpwYXNzd29yZA==
首部字段Authorization是用来告知服务器,用户代理的认证信息(证书值)。通常,想要通过服务器认证的用户代理会在接收到返回的401状态码响应后,把首部字段Authorization加入请求中。共用缓存在接收到含有Authorization首部字段的请求时的操作处理会略有差异。有关HTTP访问认证及Authorization首部字段,稍后的章节还会详细说明。另外,读者也可参阅RFC2616。
4.6 Expect
Expect: 100-continue
客户端使用首部字段Expect来告知服务器,期望出现的某种特定行为。因服务器无法理解客户端的期望作出回应而发生错误时,会返回状态码417Expectation Failed。客户端可以利用该首部字段,写明所期望的扩展。虽然HTTP/1.1规范只定义了100-continue(状态码100 Continue之意)。等待状态码100响应的客户端在发生请求时,需要指定Expect:100-continue。
6.4.7 From
首部字段From用来告知服务器使用用户代理的用户的电子邮件地址。通常,其使用目的就是为了显示搜索引擎等用户代理的负责人的电子邮件联系方式。使用代理时,应尽可能包含From首部字段(但可能会因代理不同,将电子邮件地址记录在User-Agent首部字段内)。
6.4.8 Host
虚拟主机运行在同一个IP上,因此使用首部字段Host加以区分
Host: www.hackr.jp
首部字段Host会告知服务器,请求的资源所处的互联网主机名和端口号。Host首部字段在HTTP/1.1规范内是唯一一个必须被包含在请求内的首部字段。首部字段Host和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联,这是首部字段Host必须存在的意义。请求被发送至服务器时,请求中的主机名会用IP地址直接替换解决。但如果这时,相同的IP地址下部署运行着多个域名,那么服务器就会无法理解究竟是哪个域名对应的请求。因此,就需要使用首部字段Host来明确指出请求的主机名。若服务器未设定主机名,那直接发送一个空值即可。
6.4.9 If-Match 条件请求
附带条件请求
形如If-xxx这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。只有当If-Match的字段值跟ETag值匹配一致时,服务器才会接受请求。
If-Match: "123456"
首部字段If-Match,属附带条件之一,它会告知服务器匹配资源所用的实体标记(ETag)值。这时的服务器无法使用弱ETag值。(请参照本章有关首部字段ETag的说明)服务器会比对If-Match的字段值和资源的ETag值,仅当两者一致时,才会执行请求。反之,则返回状态码412 Precondition Failed的响应。还可以使用星号(*****)指定If-Match的字段值。针对这种情况,服务器将会忽略ETag的值,只要资源存在就处理请求。
6.4.10 If-Modified-Since
如果在If-Modified-Since字段指定的日期时间后,资源发生了更新,服务器会接受请求
If-Modified-Since: Thu, 15 Apr 2004 00:00:00 GMT
首部字段If-Modified-Since,属附带条件之一,它会告知服务器若If-Modified-Since字段值早于资源的更新时间,则希望能处理该请求。而在指定If-Modified-Since字段值的日期时间之后,如果请求的资源都没有过更新,则返回状态码304 NotModified的响应。If-Modified-Since用于确认代理或客户端拥有的本地资源的有效性。获取资源的更新日期时间,可通过确认首部字段Last-Modified来确定。
6.4.11 If-None-Match
只有在If-None-Match的字段值与ETag值不一致时,可处理该请求。与If-Match首部字段的作用相反
首部字段If-None-Match属于附带条件之一。它和首部字段If-Match作用相反。用于指定If-None-Match字段值的实体标记(ETag)值与请求资源的ETag不一致时,它就告知服务器处理该请求。在GET或HEAD方法中使用首部字段If-None-Match可获取最新的资源。因此,这与使用首部字段If-Modified-Since时有些类似。
6.4.12 If-Range
首部字段If-Range属于附带条件之一。它告知服务器若指定的If-Range字段值(ETag值或者时间)和请求资源的ETag值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。
下面我们思考一下不使用首部字段If-Range发送请求的情况。服务器端的资源如果更新,那客户端持有资源中的一部分也会随之无效,当然,范围请求作为前提是无效的。这时,服务器会暂且以状态码412 Precondition Failed作为响应返回,其目的是催促客户端再次发送请求。这样一来,与使用首部字段If-Range比起来,就需要花费两倍的功夫。
6.4.13 If-Unmodified-Since
If-Unmodified-Since: Thu, 15 Apr 2004 00:00:00 GMT
**首部字段If-Unmodified-Since和首部字段If-Modified-Since的作用相反。**它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码412 Precondition Failed作为响应返回。
6.4.14 Max-Forwards
每次转发数值减1。当数值变0时返回响应
Max-Forwards: 10
通过TRACE方法或OPTIONS方法,发送包含首部字段Max-Forwards的请求时,该字段以十进制整数形式指定可经过的服务器最大数目。服务器在往下一个服务器转发请求之前,会将Max-Forwards的值减1后重新赋值。当服务器接收到Max-Forwards值为0的请求时,则不再进行转发,而是直接返回响应。
使用HTTP协议通信时,请求可能会经过代理等多台服务器。途中,如果代理服务器由于某些原因导致请求转发失败,客户端也就等不到服务器返回的响应了。对此,我们无从可知。
可以灵活使用首部字段Max-Forwards,针对以上问题产生的原因展开调查。由于当Max-Forwards字段值为0时,服务器就会立即返回响应,由此我们至少可以对以那台服务器为终点的传输路径的通信状况有所把握。
代理B到源服务器的请求失败了,但客户端不知道
6.4.15 Proxy-Authorization
Proxy-Authorization: Basic dG1w0jkpNLAGfFY5
接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段Proxy-Authorization的请求,以告知服务器认证所需要的信息。这个行为是与客户端和服务器之间的HTTP访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。客户端与服务器之间的认证,使用首部字段Authorization可起到相同作用。有关HTTP访问认证,后面的章节会作详尽阐述。
6.4.16 Range
Range: bytes=5001-10000
对于只需获取部分资源的范围请求,包含首部字段Range即可告知服务器资源的指定范围。上面的示例表示请求获取从第5001字节至第10000字节的资源。接收到附带Range首部字段请求的服务器,会在处理请求之后返回状态码为206 Partial Content的响应。无法处理该范围请求时,则会返回状态码200 OK的响应及全部资源。
6.4.17 Referer
Referer: http://www.hackr.jp/index.html
首部字段Referer会告知服务器**请求的原始资源的URI。**客户端一般都会发送Referer首部字段给服务器。但当直接在浏览器的地址栏输入URI,或出于安全性的考虑时,也可以不发送该首部字段。因为原始资源的URI中的查询字符串可能含有ID和密码等保密信息,要是写进Referer转发给其他服务器,则有可能导致保密信息的泄露。另外,Referer的正确的拼写应该是Referrer,但不知为何,大家一直沿用这个错误的拼写。
6.4.18 TE
TE: gzip, deflate; q=0.5
首部字段TE会告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段Accept-Encoding的功能很相像,但是用于传输编码。首部字段TE除指定传输编码之外,还可以指定伴随trailer字段的分块传输编码的方式。应用后者时,只需把trailers赋值给该字段值。
TE: trailers
6.4.19 User-Agent
User-Agent: Mozilla/5.0(Windows NT 6.1; WOW64; rv:13.0) Gecko/=>20100101 Firefox/13.0.1
首部字段User-Agent会将创建请求的浏览器和用户代理名称等信息传达给服务器。由网络爬虫发起请求时,有可能会在字段内添加爬虫作者的电子邮件地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称。
6.5 响应首部字段
响应首部字段是由服务器端向客户端返回响应报文中所使用的字段,用于补充响应的附加信息、服务器信息,以及对客户端的附加要求等信息。
6.5.1 Accept-Ranges
Accept-Ranges: bytes
##当不能处理范围请求时
Accept-Ranges: none
首部字段Accept-Ranges是用来告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源。可指定的字段值有两种,可处理范围请求时指定其为bytes,反之则指定其为none。
6.5.2 Age
首部字段Age能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。若创建该响应的服务器是缓存服务器,Age值是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须加上首部字段Age。
Age: 600(秒)
6.5.3 ETag
ETage: "82e22293907ce725fafa67773957acd12"
首部字段ETag能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的ETag值。另外,当资源更新时,ETag值也需要更新。生成ETag值时,并没有统一的算法规则,而仅仅是由服务器来分配。
资源被缓存时,就会被分配唯一性标识。例如,当使用中文版的浏览器访问http://www.google.com/时,就会返回中文版对应的资源,而使用英文版的浏览器访问时,则会返回英文版对应的资源。两者的URI是相同的,所以仅凭URI指定缓存的资源是相当困难的。若在下载过程中出现连接中断、再连接的情况,都会依照ETag值来指定资源。
强ETag值和弱Tag值
- 强ETag值:强ETag值,不论实体发生多么细微的变化都会改变其值。
ETage: "usagi-1234"
- 弱Tag值:弱ETag值只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变ETag值。这时,会在字段值最开始处附加W/。
ETage: W/"usagi-1234"
6.5.4 Location
Location: http://www.usagidesign.jp/sample.html
使用首部字段Location可以将响应接收方引导至某个与请求URI位置不同的资源。基本上,该字段会配合3xx:Redirection的响应,提供重定向的URI。几乎所有的浏览器在接收到包含首部字段Location的响应后,都会强制性地尝试对已提示的重定向资源的访问。
6.5.5 Proxy-Authenticate
Proxy-Authenticate: Basic realm="Usagi design Auth"
它与客户端和服务器之间的HTTP访问认证的行为相似,不同之处在于其认证行为是在客户端与代理之间进行的。而客户端与服务器之间进行认证时,首部字段WWW-Authorization有着相同的作用。有关HTTP访问认证,后面的章节会再进行详尽阐述。
首部字段Proxy-Authenticate会把由代理服务器所要求的认证信息发送给客户端。
6.5.6 Retry-After
Retry-After: 120(秒)
首部字段Retry-After告知客户端应该在多久之后再次发送请求。主要配合状态码503 ServiceUnavailable响应,或3xx Redirect响应一起使用。字段值可以指定为具体的日期时间(Wed, 04 Jul2012 06:34:24 GMT等格式),也可以是创建响应后的秒数。
6.5.7 Server
Server: Apache/2.2.17(Unix)
首部字段Server告知客户端当前服务器上安装的HTTP服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。
Server: Apache/2.2.6(Unix) PHP/5.2.5
6.5.8 Vary
当代理服务器接收到带有Vary首部字段指定获取资源的请求时,如果使用的Accept-Language字段的值相同,那么就直接从缓存返回响应。反之,则需要先从源服务器端获取资源后才能作为响应返回
Vary: Accept-Language
首部字段Vary可对缓存进行控制。源服务器会向代理服务器传达关于本地缓存使用方法的命令。从代理服务器接收到源服务器返回包含Vary指定项的响应之后,若再要进行缓存,仅对请求中含有相同Vary指定首部字段的请求返回缓存。即使对相同资源发起请求,但由于Vary指定的首部字段不相同,因此必须要从源服务器重新获取资源。
6.5.9 WWW-Authenticate
WWW-Authenticate: Basic realm="Usagide sign Auth"
首部字段WWW-Authenticate用于HTTP访问认证。它会告知客户端适用于访问请求URI所指定资源的认证方案(Basic或是Digest)和带参数提示的质询(challenge)。状态码401Unauthorized响应中,肯定带有首部字段WWW-Authenticate。
上述示例中,realm字段的字符串是为了辨别请求URI指定资源所受到的保护策略。有关该首部,请参阅本章之后的内容。
6.6 实体首部字段
实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。
6.6.1 Allow
Allow: GET, HEAD
首部字段Allow用于通知客户端能够支持Request-URI指定资源的所有HTTP方法。当服务器接收到不支持的HTTP方法时,会以状态码405 MethodNot Allowed作为响应返回。与此同时,还会把所有能支持的HTTP方法写入首部字段Allow后返回.
6.6.2 Content-Encoding
Content-Encoding: gzip
首部字段Content-Encoding会告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩。主要采用以下4种内容编码的方式,gzip, compress, deflate, identity。(各方式的说明请参考6.4.3节Accept-Encoding首部字段)。
6.6.3 Content-Language
Content-Language: zh-CN
首部字段Content-Language会告知客户端,实体主体使用的自然语言(指中文或英文等语言)。
6.6.4 Content-Length
Content-Length: 15000
首部字段Content-Length表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用Content-Length首部字段。由于实体主体大小的计算方法略微复杂,所以在此不再展开。读者若想一探究竟,可参考RFC2616的4.4。
6.6.5 Content-Location
Content-Location: http://www.hackr.jp/index-ja.html
首部字段Content-Location给出与报文主体部分相对应的URI。和首部字段Location不同,Content-Location表示的是报文主体返回资源对应的URI。比如,对于使用首部字段Accept-Language的服务器驱动型请求,当返回的页面内容与实际请求的对象不同时,首部字段Content-Location内会写明URI。(访问http://www.hackr.jp/返回的对象却是http://www.hackr.jp/index-ja.html等类似情况)
6.6.6 Content-MD5
客户端会对接收的报文主体执行相同的MD5算法,然后与首部字段Content-MD5的字段值比较
Content-MD5: 0GFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==
首部字段Content-MD5是一串由MD5算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达。
对报文主体执行MD5算法获得的128位二进制数,再通过Base64编码后将结果写入Content-MD5字段值。由于HTTP首部无法记录二进制值,所以要通过Base64编码处理。为确保报文的有效性,作为接收方的客户端会对报文主体再执行一次相同的MD5算法。计算出的值与字段值作比较后,即可判断出报文主体的准确性。
采用这种方法,对内容上的偶发性改变是无从查证的,也无法检测出恶意篡改。其中一个原因在于,内容如果能够被篡改,那么同时意味着Content-MD5也可重新计算然后被篡改。所以处在接收阶段的客户端是无法意识到报文主体以及首部字段Content-MD5是已经被篡改过的。
6.6.7 Content-Range
Content-Range: bytes 5001-10000/10000
针对范围请求,返回响应时使用的首部字段Content-Range,能告知客户端作为响应返回的实体的哪个部分符合范围请求。字段值以字节为单位,表示当前发送部分及整个实体大小。
6.6.8 Content-Type
Content-Type: text/html; charset=UTF-8
首部字段Content-Type说明了实体主体内对象的媒体类型。和首部字段Accept一样,字段值用type/subtype形式赋值。参数charset使用iso-8859-1或euc-jp等字符集进行赋值。
6.6.9 Expires
Expires: Wed, 04 Jul 2012 08:26:05 GMT
首部字段Expires会将资源失效的日期告知客户端。缓存服务器在接收到含有首部字段Expires的响应后,会以缓存来应答请求,在Expires字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。源服务器不希望缓存服务器对资源缓存时,最好在Expires字段内写入与首部字段Date相同的时间值。但是,当首部字段Cache-Control有指定max-age指令时,比起首部字段Expires,会优先处理max-age指令。
6.6.10 Last-Modified
Last-Modified: Wed, 04 Jul 2012 08:26:05 GMT
首部字段Last-Modified指明资源最终修改的时间。一般来说,这个值就是Request-URI指定资源被修改的时间。但类似使用CGI脚本进行动态数据处理时,该值有可能会变成数据最终修改时的时间。
6.7 为Cookie服务的首部字段
管理服务器与客户端之间状态的Cookie,虽然没有被编入标准化HTTP/1.1的RFC2616中,但在Web网站方面得到了广泛的应用。
Cookie的工作机制是用户识别及状态管理。Web网站为了管理用户的状态会通过Web浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该Web网站时,可通过通信方式取回之前存放的Cookie。
调用Cookie时,由于可校验Cookie的有效期,以及发送方的域、路径、协议等信息,所以正规发布的Cookie内的数据不会因来自其他Web站点和攻击者的攻击而泄露。
至2013年5月,Cookie的规格标准文档有以下4种。
-
由网景公司颁布的规格标准:网景通信公司设计并开发了Cookie,并制定相关的规格标准。1994年前后,Cookie正式应用在网景浏览器中。目前最为普及的Cookie方式也是以此为基准的。
-
RFC2109:某企业尝试以独立技术对Cookie规格进行标准化统筹。原本的意图是想和网景公司制定的标准交互应用,可惜发生了微妙的差异。现在该标准已淡出了人们的视线。
-
RFC2965:为终结Internet Explorer浏览器与NetscapeNavigator的标准差异而导致的浏览器战争,RFC2965内定义了新的HTTP首部Set-Cookie2和Cookie2。可事实上,它们几乎没怎么投入使用。
-
RFC6265:将网景公司制定的标准作为业界事实标准(De facto standard),重新定义Cookie标准后的产物。
目前使用最广泛的Cookie标准却不是RFC中定义的任何一个。而是在网景公司制定的标准上进行扩展后的产物。
为Cookie服务的首部字段
Set-Cookie: status=enable; expires= Tue, 05 Jul 2011 07:26:21 GMT; =>path=/; domain=.hackr.jp;
当服务器准备开始管理客户端的状态时,会事先告知各种信息。
Set-Cookie字段的属性
-
expires属性:Cookie的expires属性指定浏览器可发送Cookie的有效期。当省略expires属性时,其有效期仅限于维持浏览器会话(Session)时间段内。这通常限于浏览器应用程序被关闭之前。另外,一旦Cookie从服务器端发送至客户端,服务器端就不存在可以显式删除Cookie的方法。但可通过覆盖已过期的Cookie,实现对客户端Cookie的实质性删除操作。
-
path属性:Cookie的path属性可用于限制指定Cookie的发送范围的文件目录。不过另有办法可避开这项限制,看来对其作为安全机制的效果不能抱有期待。
-
domain属性:通过Cookie的domain属性指定的域名可做到与结尾匹配一致。比如,当指定example.com后,除example.com以外,www.example.com或www2.example.com等都可以发送Cookie。因此,除了针对具体指定的多个域名发送Cookie之外,不指定domain属性显得更安全。
-
secure属性:Cookie的secure属性用于限制Web页面仅在HTTPS安全连接时,才可以发送Cookie。发送Cookie时,指定secure属性的方法如下所示。
Set-Cookie: name=value;secure
以上例子仅当在https://www.example.com/(HTTPS)安全连接的情况下才会进行Cookie的回收。也就是说,即使域名相同,http://www.example.com/(HTTP)也不会发生Cookie回收行为。当省略secure属性时,不论HTTP还是HTTPS,都会对Cookie进行回收。
- HttpOnly属性:Cookie的HttpOnly属性是Cookie的扩展功能,它使JavaScript脚本无法获得Cookie。其主要目的为防止跨站脚本攻击(Cross-site scripting,XSS)对Cookie的信息窃取。发送指定HttpOnly属性的Cookie的方法如下所示。
Set-Cookie: name=value;HttpOnly
通过上述设置,通常从Web页面内还可以对Cookie进行读取操作。但使用JavaScript的document.cookie就无法读取附加HttpOnly属性后的Cookie的内容了。因此,也就无法在XSS中利用JavaScript劫持Cookie了。虽然是独立的扩展功能,但Internet Explorer 6SP1以上版本等当下的主流浏览器都已经支持该扩展了。另外顺带一提,该扩展并非是为了防止XSS而开发的。
6.7.2 Cookie
Cookie: status=enable
首部字段Cookie会告知服务器,当客户端想获得HTTP状态管理支持时,就会在请求中包含从服务器接收到的Cookie。接收到多个Cookie时,同样可以以多个Cookie形式发送。
6.8 其他首部字段
HTTP首部字段是可以自行扩展的。所以在Web服务器和浏览器的应用上,会出现各种非标准的首部字段。接下来,我们就一些最为常用的首部字段进行说明。X-Frame-Options、X-XSS-Protection、DNT、P3P
6.8.1 X-Frame-Options
X-Frame-Options: DENY
首部字段X-Frame-Options属于HTTP响应首部,用于控制网站内容在其他Web网站的Frame标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击。
首部字段X-Frame-Options有以下两个可指定的字段值。DENY:拒绝。SAMEORIGIN:仅同源域名下的页面(Top-level-browsing-context)匹配时许可。(比如,当指定http://hackr.jp/sample.html页面为SAMEORIGIN时,那么hackr.jp上所有页面的frame都被允许可加载该页面,而example.com等其他域名的页面就不行了)
支持该首部字段的浏览器有:Internet Explorer8、Firefox 3.6.9+、Chrome 4.1.249.1042+、Safari 4+和Opera 10.50+ 等。现在主流的浏览器都已经支持。能在所有的Web服务器端预先设定好X-Frame-Options字段值是最理想的状态。
6.8.2X-XSS-Protection
X-XSS-Protection: 1
首部字段X-XSS-Protection属于HTTP响应首部,它是针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器XSS防护机制的开关。
首部字段X-XSS-Protection可指定的字段值如下。
-
0 :将XSS过滤设置成无效状态
-
1 :将XSS过滤设置成有效状态
6.8.3 DNT
DNT: 1
首部字段DNT属于HTTP请求首部,其中DNT是Do Not Track的简称,意为拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。首部字段DNT属于HTTP请求首部,其中DNT是Do Not Track的简称,意为拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。
首部字段DNT可指定的字段值如下。
-
0 :同意被追踪
-
1 : 拒绝被追踪
由于首部字段DNT的功能具备有效性,所以Web服务器需要对DNT做对应的支持。
6.8.4 P3P
P3P: CP="CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa => IVAa IVDa OUR BUS IND UNI COM NAV INT"
首部字段P3P属于HTTP响应首部,通过利用**P3P(The Platform for Privacy Preferences,在线隐私偏好平台)**技术,可以让Web网站上的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的目的。
要进行P3P的设定,需按以下操作步骤进行。
步骤1: 创建P3P隐私
步骤2: 创建P3P隐私对照文件后,保存命名在/w3c/p3p.xml
步骤3: 从P3P隐私中新建Compact policies后,输出到HTTP响应中
有关P3P的详细规范标准请参看下方链接。●The Platform for Privacy Preferences 1.0(P3P1.0)Specificationhttp://www.w3.org/TR/P3P/
Tips:(协议中对X-前缀的废除)在HTTP等多种协议中,通过给非标准参数加上前缀X-,来区别于标准参数,并使那些非标准的参数作为扩展变成可能。但是这种简单粗暴的做法有百害而无一益,因此在“RFC6648- Deprecating the “X-” Prefix andSimilar Constructs in ApplicationProtocols”中提议停止该做法。然而,对已经在使用中的X-前缀来说,不应该要求其变更。