# 图解HTTP
第 1 章 了解Web及网络基础
1.1使用http协议访问web
客户端:通过发送请求获取服务器资源的Web浏览器等。
Web使用一种名为 HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器端等一系列运作流程。而协议是指规则的约定。可以说,Web是建立在HTTP协议上通信的。
1.2 HTTP的诞生
1.2.1 为知识共享而规划Web
最初的基本理念:借助多文档之间相互关联形成的超文本(HyperText),连成可相互参阅的WWW(World Wide Web,万维网)。
现在提出了3项WWW构建技术,分别是:把SGML(Standard Generalized markup Language,标准通用标记语言)作为页面的文本标记语言的HTML(HyperText Markup Language,超文本标记语言);作为文档传递协议的HTTP;指定文档所在地址的URL(Uniform Resource Locatou,统一资源定位符)。
WWW这一名称,是Web浏览器当年用来浏览超文本的客户端应用程序时的名称。现在则用来表示这一系列的集合,也可称为Web。
1995年微软与网景爆发浏览器大战。2000年前后随着网景通信公司的衰落而告一段落。04年,Mozilla基金会发布了Firefox浏览器,第二次浏览器大战随即爆发。
HTTP于1990年问世。那时的HTTP并没有作为正式的标准被建立。现在的HTTP其实含有HTTP1.0之前版本的意思,因此被称为HTTP/0.9。
HTTP/1.0:作为标准被公布(1996年5月),版本被命名为HTTP/1.0。
HTTP/1.1: 97年1月公布,是目前主流的HTTP协议版本。当初的标准是RFC2068,之后发布的修订版RFC2626就是当前的最新版本。
2.0在修订,但是离普及还有很远一段路。
1.3 网络基础TCP/IP
通常使用的网络(包括互联网)是在TCP/IP协议族的基础上运作的。而HTTP属于它内部的一个子集。
计算机与网络设备要相互通信,双方就必须基于相同的方法。而我们就把这种规则称为 协议。(protocol)
TCP/IP是互联网相关的各类协议族的总称。也有说法认为,TCP/IP是指TCP和IP这两种协议。还有一种说法认为,TCP/IP是在IP协议的通信过程中,使用到的协议族的统称。
1.3.2 TCP/IP的分层管理
TCP/IP协议族按层次分别分为以下4层:应用层、传输层、网络层和数据链路层。
层次化之后,设计简单,替换方便。
应用层: 应用层决定了向用户提供应用服务时通信的活动。
TCP/IP协议族内预存了各类通用的应用服务。比如,FTP(File Transfer Protocol,文件传输协议)和DNS(Domain Name System,域名系统)服务就是其中的两类。
HTTP协议也处于该层。
传输层: 传输层对上层应用层,提供处于网络连接中的两台计算机之间的数据传输。
在传输层有两个性质不同的协议:TCP(Transmission Control Protocol,传输控制协议)和UDP(User Data Protocol,用户数据报协
议)。
网络层(又名网络互连层): 网络层用来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。该层规定了通过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方。
与对方计算机之间通过多台计算机或网络设备进行传输时,网络层所起的作用就是在众多的选项内选择一条传输路线。
链路层(又名数据链路层,网络接口层): 用来处理连接网络的硬件部分。包括控制操作系统、硬件的设备驱动、NIC(Network Interface Card,网络适配器,即网卡),及光纤等物理可见部分(还包括连接器等一切传输媒介)。硬件上的范畴均在链路层的作用范围之内。
1.3.3 TCP/IP通信传输流
利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则往应用层往上走。
我们用HTTP举例来说明,首先作为发送端的客户端在应用层(HTTP协议)发出一个想看某个Web页面的HTTP请求。
接着,为了传输方便,在传输层(TCP协议)把从应用层处收到的数据(HTTP请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。
在网络层(IP协议),增加作为通信目的地的MAC地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。
发送端在层与层之间传输数据时,没经过一层时必定会被打上一个该层所属的首部信息。反之,接收端在层与层传输数据时,没经过一层时会把对应的首部消去。
封装(encapsulate):这种把数据包装起来的做法。
1.4 与HTTP关系密切的协议:IP/TCP和DNS
1.4.1 负责传输的IP协议
按层次分,IP(Internet Protocol)网际协议位于网络层。几乎所有使用网络的系统都会用到IP协议。
IP和IP地址不是一回事。这里的 IP其实是一种协议的名称。
IP协议的作用是把各种数据包传送给对方。而要保证确实传送到对方那里,则需要满足各类条件。其中两个重要的条件是IP地址和MAC地址(Media Access Control Address)。
IP地址指明了节点被分配到的地址,MAC地址是指网卡所属的固定地址。IP地址可以和MAC地址进行配对。IP地址可变换,但MAC地址基本上不会更改。
1.4.2 使用ARP协议凭借MAC地址进行通信
IP间的通信依赖MAC地址。在网络上,通信的双方在同一局域网(LAN)内的情况是很少的,通常是经过多台计算机和网络设备中转才能连接到对方。而在进行中转时,会利用下一站中转设备的MAC地址来搜索下一个中转目标。这时,会采用ARP协议(Address Resolution Protocol)。ARP是一种用以解析地址的协议,根据通信方的IP地址就可以反查出对方的MAC地址。
没有人能够全面掌握互联网中的传输状况
在到达通信目标前的中转过程中,那些计算机和路由器等网络设备只能获悉很粗略的传输路线。
这种机制称为路由选择。(routing)(中转)
1.4.2 确保可靠性的TCP协议
按层次分,TCP位于传输层,提供可靠的字节流服务。
字节流服务(Byte Stream Service)是指,为了方便传输,将大块数据分割成以报文段(segment)为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。
一言以蔽之,TCP协议为了更容易传送大数据才把数据分割,而且TCP协议能够确认数据最终是否送达到对方。
确保数据能到达目标
为了准确无误地将数据送达目标处,TCP协议采用了三次握手(three-way handshaking)策略。用TCP协议把数据包送出去后,TCP不会对传送后的情况置之不理,它一定会向对方确认是否成功送达。握手过程中使用了TCP的标志(flag)----SYN(synchronize)和 ACK(acknowledgement)。
发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。最后,发送端再回传一个带ACK标志的数据包,代表 “握手” 结束。
若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。
1.5 负责域名解析的DNS服务
DNS(Domain Name System)服务是和 HTTP 协议一样位于应用层的协议。它提供域名到IP地址之间的解析服务。
计算机既可以被赋予IP地址,也可以被赋予主机名和域名。用户通常用主机名和域名,因为好记,而计算机擅长处理数字。
为了解决上述问题,DNS服务应运而生。DNS协议提供通过域名查找IP地址,或逆向从IP地址反查域名的服务。
1.6 各种协议与 HTTP 协议的关系
客户端想要浏览某个页面,比如是https:www.google.com
,要经历如下步骤:
1.DNS解析,DNS服务器根据域名返回对应IP地址。
2.HTTP协议,生成针对目标Web服务器的HTTP请求报文。
3.TCP协议,为了方便通信,将HTTP请求报文分割成报文段,按序号分别多个报文段,把每个报文段可靠(三次握手)的传给对方。
4.IP协议,搜索对方的地址,一边中转一边传送。
5.TCP协议,重组从对方那里接受到的报文段,按序号以原来的顺序重组请求报文。
6.HTTP,对Web服务器请求的内容的处理。
请求的处理结果也同样利用TCP/IP通信协议向用户进行回传
1.7 URI和URL
与 URI (统一资源标识符)相比,我们更熟悉 URL ( Uniform Resource Locator ,统一资源定位符)。 URL正是使用 Web 浏览器等访问 Web 页面时需要输入的网页地址。
1.7.1 统一资源标识符
URI 是 Uniform Resource Identifier 的缩写。 RFC2396 分别对这 3 个单词进行了如下定义。
Uniform
规定统一的格式可方便处理多种不同类型的资源,而不用根据上下文环境来识别资源指定的访问方式。另外,加入新增的协议方案(如 http: 或 ftp: )也更容易。
Resource
资源的定义是 “ 可标识的任何东西 ” 。除了文档文件、图像或服务(例如当天的天气预报)等能够区别于其他类型的,全都可作为资源。另外,资源不仅可以是单一的,也可以是多数的集合体。
Identifier
表示可标识的对象。也称为标识符。
综上所述, URI 就是由某个协议方案表示的资源的定位标识符。协议方案是指访问资源所使用的协议类型名称。
采用 HTTP 协议时,协议方案就是 http 。除此之外,还有 ftp 、 mailto 、 telnet 、 file 等。标准的 URI
协议方案有30种左右。
URI 用字符串标识某一互联网资源,而 URL 表示资源的地点(互联网上所处的位置)。可见 URL
是 URI
的子集。
在充分理解的基础上,也可用 URL 替换 URI 。
1.7.2 URI格式
表示指定的 URI,要使用涵盖全部必要信息的绝对 URI、绝对 URL 以及相对 URL 。相对 URL ,是指从浏览器中基本 URI 处指定的 URL ,形如 /image/logo.gif 。
绝对URI格式
http://user:pass@www.example.jp:80/dir/index.htm?uid=1#ch1
http://
: 协议/方案名
使用 http: 或 https: 等协议方案名获取访问资源时要指定协议类型。不区分字母大小写,最后附一个冒号( : )。
user:pass
: 登录信息(认证)
指定用户名和密码作为从服务器端获取资源时必要的登录信息(身份认证)。此项是可选项。
www.example.jp
: 服务器地址
使用绝对 URI 必须指定待访问的服务器地址。地址可以是类似 hackr.jp
这种 DNS
可解析的名称,或是 192.168.1.1
这类 IPv4
地址 名,还可以是 [0:0:0:0:0:0:0:1]
这样用方括号括起来的 IPv6
地址名。
80
: 服务器端口号
指定服务器连接的网络端口号。此项也是可选项,若用户省略则自动使用默认端口号。
dir/index.htm
: 带层次的文件路径
指定服务器上的文件路径来定位特指的资源。这与 UNIX 系统的文件目录结构相似。
uid=1
: 查询字符串
针对已指定的文件路径内的资源,可以使用查询字符串传入任意参数。此项可选。
ch1
: 片段标识符
使用片段标识符通常可标记出已获取资源中的子资源(文档内的某个位置)。但在 RFC
中并没有明确规定其使用方法。该项也为可选项。
RFC
: 有一些用来制定 HTTP 协议技术标准的文档,它们被称为 RFC ( Request for Comments ,征求修正意
见书)。
第 2 章 简单的HTTP协议
2.1 HTTP协议用于客户端和服务器端之间的通信
HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同,用于客户端和服务器之间的通信。
请求访问文本或图像等资源的一端称为客户端,而提供资源响应的一端称为服务器端。
应用 HTTP 协议时,必定是一端担任客户端角色,另一端担任服务器端角色。
有时候,按实际情况,两台计算机作为客户端和服务器端的角色有可能会互换。但就仅从一条通信路线来说,服务器端和客户端的角色是确定的,而用 HTTP 协议能够明确区分哪端是客户端,哪端是服务器端。
2.2 通过请求和响应的交换达成通信
HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。
GET /index.htm HTTP/1.1
Host: hackr.jp
起始行开头的 GET 表示请求访问服务器的类型,称为方法( method )。随后的字符串 /index.htm 指明了请求访问的资源对象,也叫做请求 URI ( request-URI )。最后的 HTTP/1.1 ,即 HTTP 的版本号,用来提示客户端使用的 HTTP 协议功能。
综合来看,这段请求内容的意思是:请求访问某台 HTTP 服务器上的 /index.htm 页面资源。
请求报文是由请求方法、请求 URI 、协议版本、可选的请求首部字段和内容实体构成的。
POST /form/entry HTTP/1.1
方法 URI 协议版本
Host: hackr.jp
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length" 16
请求首部字段
name-uenomage-37
内容实体
接收到请求的服务器,会将请求内容的处理结果以响应的形式返回。
HTTP/1.1 200 OK
协议版本 状态码 状态码的原因短语
Date: Tue, 10 Jul 2012 06:50:15 GMT
Content-Length: 362
Content-Type: text/html
响应首部字段
<html>
……
主体
在起始行开头的 HTTP/1.1 表示服务器对应的 HTTP 版本。
紧挨着的 200 OK 表示请求的处理结果的状态码( status code )和原因短语( reason-phrase )。下一行显示了创建响应的日期时间,是首部字段( header field )内的一个属性。
接着以一空行分隔,之后的内容称为资源实体的主体( entity body )。
响应报文基本上由协议版本、状态码(表示请求成功或失败的数字代码)、用以解释状态码的原因短语、可选的响应首部字段以及实体主体构成。
2.3 HTTP 是不保存状态的协议
HTTP 是一种不保存状态,即无状态( stateless )协议。 HTTP 协议自身不对请求和响应之间的通信状态进行保存。也就是说在 HTTP 这个级别,协议对于发送过的请求或响应都不做持久化处理。
使用 HTTP 协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。
可是,随着 Web 的不断发展,因无状态而导致业务处理变得棘手的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能够掌握是谁送出的请求,需要保存用户的状态。
HTTP/1.1 虽然是无状态协议,但为了实现期望的保持状态功能,于是引入了 Cookie 技术。有了 Cookie 再用 HTTP 协议通信,就可以管理状态了。
2.4 请求 URI 定位资源
当客户端请求访问资源而发送请求时, URI 需要将作为请求报文中的请求 URI 包含在内。
URI为完整的请求URI
GET http://hackr.jp/index.htm HTTP/1.1
在首部字段Host中写明网络域名或IP地址
GET /index.htm HTTP/1.1
Host: hackr.jp
除此之外,如果不是访问特定资源而是对服务器本身发起请求,可以用一个 * 来代替请求 URI 。下面这个例子是查询 HTTP 服务器端支持 的 HTTP 方法种类。
OPTIONS * HTTP/1.1
2.5 告知服务器意图的 HTTP 方法
GET
: 获取资源
GET 方法用来请求访问已被 URI 识别的资源。指定的资源经服务器端解析后返回 响应内容。也就是说,如果请求的资源是文本,那就保持原样返回;如果是像 CGI ( Common Gateway Interface ,通用网关接口)那样的程序,则返回经过执行后的输出结果。
请求:GET /index.html HTTP/1.1
Host:www.hackr.jp
响应:返回index.html的页面资源
请求:GET /index.html HTTP/1.1
Host:www.hackr.jp
If-Modified-Since: Thu, 12 Jul 2012 07:30:00 GMT
响应:仅返回 2012 年 7 月 12 日 7 点 30 分以后更新过的 index.html 页面资源。如果未有内容更新,则以状态码 304 Not Modified 作为响应返回
POST
: 传输实体主体
虽然用 GET 方法也可以传输实体的主体,但一般不用 GET 方法进行传输,而是用 POST 方法。虽说 POST
的功能与 GET 很相似,但 POST 的主要目的并不是获取响应的主体内容。
请求:POST /submit.cgi HTTP/1.1
Host: www.hackr.jp
Content-Length: 1560 ( 1560 字节的数
据)
响应:返回 submit.cgi 接收数据的处理结果
PUT
: 传输文件
PUT 方法用来传输文件。就像 FTP 协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。
但是,鉴于 HTTP/1.1 的 PUT 方法自身不带验证机制,任何人都可以上传文件 , 存在安全性问题,因此一般
的 Web 网站不使用该方法。若配合 Web 应用程序的验证机制,或架构设计采用 REST ( REpresentational
State Transfer ,表征状态转移)标准的同类 Web 网站,就可能会开放使用 PUT 方法。
请求:PUT /example.html HTTP/1.1
Host: www.hackr.jp
Content-Type: text/html
Content-Length: 1560 ( 1560 字节的数据)
响应:响应返回状态码 204 No Content (比如 :该 html 已存在于服务器上)
此处响应的意思其实是请求执行成功了,但无数据返回。
HEAD
: 获得报文首部
HEAD 方法和 GET 方法一样,只是不返回报文主体部分。用于确认 URI 的有效性及资源更新的日期时间等。
请求:HEAD /index.html HTTP/1.1
Host: www.hackr.jp
响应:返回 index.html 有关的响应首部
DELETE
: 删除文件
DELETE 方法用来删除文件,是与 PUT 相反的方法。 DELETE 方法按请求 URI 删除指定的资源。
但是, HTTP/1.1 的 DELETE 方法本身和 PUT 方法一样不带验证机制,所以一般的 Web 网站也不使用 DELETE 方法。当配合 Web 应用程序的验证机制,或遵守 REST 标准时还是有可能会开放使用的。
请求:DELETE /example.html HTTP/1.1
Host: www.hackr.jp
响应:响应返回状态码 204 No Content (比如 :该 html 已从该服务器上删除)
OPTIONS
: 询问支持的方法
OPTIONS 方法用来查询针对请求 URI 指定的资源支持的方法。
请求:OPTIONS * HTTP/1.1
Host: www.hackr.jp
响应:HTTP/1.1 200 OK
Allow: GET, POST, HEAD,
OPTIONS
(返回服务器支持的方法)
TRACE
: 追踪路径
TRACE 方法是让 Web 服务器端将之前的请求通信环回给客户端的方法。
发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器端就将该数字减 1 ,当数值刚好减到 0 时,就停止继续传输,最后接收到请求的服务器端则返回状态码 200 OK的响应。
客户端通过 TRACE 方法可以查询发送出去的请求是怎样被加工修改 / 篡改的。这是因为,请求想要连接到源目标服务器可能会通过代理中转, TRACE 方法就是用来确认连接过程中发生的一系列操作。
但是, TRACE 方法本来就不怎么常用,再加上它容易引发 XST ( Cross-Site Tracing ,跨站追踪)攻击,通常就更不会用到了。
请求:TRACE / HTTP/1.1
Host: hackr.jp
Max-Forwards: 2
响应:HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 1024
TRACE / HTTP/1.1
Host: hackr.jp
Max-Forwards: 2 (返回响应包含请求内
容)
CONNECT
: 要求用隧道协议连接代理
CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP通信。主要使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全) 协议把通信内容加密后经网络隧道传输。
CONNECT 代理服务器名 : 端口号 HTTP 版本
请求:CONNECT proxy.hackr.jp:8080 HTTP/1.1
Host: proxy.hackr.jp
响应:HTTP/1.1 200 OK (之后进入网络隧道)
2.6 使用方法下达命令
向请求 URI 指定的资源发送请求报文时,采用称为方法的命令。
方法的作用在于,可以指定请求的资源按期望产生某种行为。方法中有 GET 、 POST 和 HEAD 等。
方法 | 说明 | 支持的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 |
2.7 持久连接节省通信量
HTTP 协议的初始版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。
以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大问题。可随着 HTTP 的普及,文档中包含大量图片的情况多了起来。
比如,使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的开销。
2.7.1 持久连接
为解决上述 TCP 连接的问题, HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接( HTTP Persistent Connections ,也称为 HTTP keep-alive 或 HTTP connection reuse)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。
持久连接旨在建立 1 次 TCP 连接后进行多次请求和响应的交互。
持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外,减少开销的那部分时间,使 HTTP 请求和响应能够更早地结束,这样 Web 页面的显示速度也就相应提高了。
在 HTTP/1.1 中,所有的连接默认都是持久连接,但在 HTTP/1.0 内并未标准化。虽然有一部分服务器通过非标准的手段实现了持久连接,但服务器端不一定能够支持持久连接。毫无疑问,除了服务器端,客户端也需要支持持久连接。
2.7.2 管线化
持久连接使得多数请求以管线化( pipelining )方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,不用等待响应亦可直接发送下一个请求。
这样就能够做到同时并行发送多个请求,而不需要一个接一个地等待响应了。
比如,当请求一个包含 10 张图片的 HTML Web 页面,与挨个连接相比,用持久连接可以让请求更快结束。
而管线化技术则比持久连接还要快。请求数越多,时间差就越明显。
2.8 使用 Cookie 的状态管理
HTTP 是无状态协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。
假设要求登录认证的 Web 页面本身无法进行状态的管理(不记录已登录的状态),那么每次跳转新页面不是要再次登录,就是要在每次请求报文中附加参数来管理登录状态。
不可否认,无状态协议当然也有它的优点。由于不必保存状态,自然可减少服务器的 CPU 及内存资源的消耗。从另一侧面来说,也正是因为 HTTP 协议本身是非常简单的,所以才会被应用在各种场景里。
保留无状态协议这个特征的同时又要解决类似的矛盾问题,于是引入了 Cookie 技术。 Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。
Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie 。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。
服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。
1、请求报文(没有 Cookie 信息的状态)
GET /reader/ HTTP/1.1
Host: hackr.jp
* 首部字段内没有 Cookie 的相关信息
2、响应报文(服务器端生成 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=UTF-8
3、请求报文(自动发送保存着的 Cookie 信息)
GET /image/ HTTP/1.1
Host: hackr.jp
Cookie: sid=1342077140226724
第 3 章 HTTP报文内的HTTP信息
3.1 HTTP报文
用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。 HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。
HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行( CR+LF )来划分。通常,并不一定要有报文主体。
报文首部 | 【报文首部】服务器端或客户端处理的请求或响应的内容及属性 | |
---|---|---|
空行(CR+LF) | CR(Carrage Return,回车符:16进制0x0d)和LF(Line Feed,换行符:16进制0x0a) | |
报文主体 | 应被发送的数据 |
3.2 请求报文及响应报文的结构
请求行
请求首部字段
通用首部字段
实体首部字段
其他
状态行
响应首部字段
通用首部字段
实体首部字段
其他
请求报文和响应报文的首部内容由以下数据组成。
请求行
: 包含用于请求的方法,请求你URI和HTTP版本。
状态行
: 包含表明响应结果的状态码,原因短语和HTTP版本。
首部字段
: 包含表示请求和响应的各种条件和属性的各类首部。
一般有4种首部,分别是:通用首部、请求首部、响应首部和实体首部。
其他
: 可能包含HTTP的RFC里未定义的首部(Cookie等)
3.3 编码提升传输速率
HTTP 在传输数据时可以按照数据原貌直接传输,但也可以在传输过程中通过编码提升传输速率。通过在传输时编码,能有效地处理大量的访问请求。但是,编码的操作需要计算机来完成,因此会消耗更多的 CPU 等资源。
3.3.1 报文主体和实体主体的差异
报文(message)
: 是HTTP通信中的基本单位,由 8 位组字节流(octet sequence,其中 octet 为 8 个比特)组成,通过 HTTP 通信传输。
实体(entity)
: 作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。
HTTP 报文的主体用于传输请求或响应的实体主体。
通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。
报文和实体这两个术语在之后会经常出现,请事先理解两者的差异。
3.3.2 压缩传输的内容编码
向待发送邮件内增加附件时,为了使邮件容量变小,我们会先用 ZIP压缩文件之后再添加附件发送。 HTTP协议中有一种被称为内容编码的功能也能进行类似的操作。
内容编码指明应用在实体内容上的编码格式,并保持实体信息原样压缩。内容编码后的实体由客户端接收并负责解码。
常用的内容编码有以下几种:
- gzip ( GNU zip )
- compress ( UNIX 系统的标准压缩)
- deflate ( zlib )
- identity (不进行编码)
3.3.3 分割发送的分块传输编码
在 HTTP 通信过程中,请求的编码实体资源尚未全部传输完成之前,浏览器无法显示请求页面。在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。
这种把实体主体分块的功能称为分块传输编码( Chunked Transfer Coding)。
分块传输编码会将实体主体分成多个部分(块)。每一块都会用十六进制来标记块的大小,而实体主体的最后一块会使用 “0(CR+LF)” 来标记。
使用分块传输编码的实体主体会由接收的客户端负责解码,恢复到编码前的实体主体。
HTTP/1.1中存在一种称为传输编码(Transfer Coding)的机制,它可以在通信时按某种编码方式传输,但只定义作用于分块传输编码中。
3.4 发送多种数据的多部分对象集合
发送邮件时,我们可以在邮件里写入文字并添加多份附件。这是因为采用了 MIME ( Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)机制,它允许邮件处理文本、图片、视频等多个不同类型的数据。例如,图片等二进制数据以 ASCII 码字符串编码的方式指明,就是利用 MIME 来描述标记数据类型。而在 MIME 扩展中会使用一种称为多部分对象集合( Multipart)的方法,来容纳多份不同类型的数据。
相应地, HTTP 协议中也采纳了多部分对象集合,发送的一份报文主体内可含有多类型实体。通常是在图片或文本文件等上传时使用。
多部分对象集合包含的对象如下:
multipart/form-data
: 在 Web 表单文件上传时使用。
multipart/byteranges
: 状态码 206 ( Partial Content ,部分内容)响应报文包含了多个范围的内容时使用。
在 HTTP 报文中使用多部分对象集合时,需要在首部字段里加上 Content-type 。有关这个首部字段,我们稍后讲解。
3.5 获取部分内容的范围请求
以前,用户不能使用现在这种高速的带宽访问互联网,当时,下载一个尺寸稍大的图片或文件就已经很吃力了。如果下载过程中遇到网络中断的情况,那就必须重头开始。为了解决上述问题,需要一种可恢复的机制。所谓恢复是指能从之前下载中断处恢复下载。
要实现该功能需要指定下载的实体范围。像这样,指定范围发送的请求叫做范围请求( Range Request )。
对一份 10 000字节大小的资源,如果使用范围请求,可以只请求 5001~10 000 字节内的资源。
执行范围请求时,会用到首部字段 Range 来指定资源的 byte 范围。
byte 范围的指定形式如下:
- 5001~10 000 字节
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.6 内容协商返回最合适的内容
同一个 Web 网站有可能存在着多份相同内容的页面。比如英语版和中文版的 Web 页面,它们内容上虽相同,但使用的语言却不同。
当浏览器的默认语言为英语或中文,访问相同 URI 的 Web 页面时,则会显示对应的英语版或中文版的 Web 页面。这样的机制称为内容协商( Content Negotiation )。
内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。
包含在请求报文中的某些首部字段(如下)就是判断的基准。
- Accept
- Accept-Charset
- Accept-Encoding
- Accept-Language
- Content-Language
内容协商技术有以下 3 种类型:
服务器驱动协商( Server-driven Negotiation )
: 由服务器端进行内容协商。以请求的首部字段为参考,在服务器端自动处理。但对用户来说,以浏览器发送的信息作为判定的依据,并不一定能筛选出最优内容。
客户端驱动协商( Agent-driven Negotiation )
: 由客户端进行内容协商的方式。用户从浏览器显示的可选项列表中手动选择。还可以利用 JavaScript 脚本在 Web 页面上自动进行上述选择。比如按 OS 的类型或浏览器类型,自行切换成 PC 版页面或手机版页面。
透明协商( Transparent Negotiation )
: 是服务器驱动和客户端驱动的结合体,是由服务器端和客户端各自进行内容协商的一种方法。
第 4 章 返回结果的 HTTP 状态码
4.1 状态码告知从服务器端返回的请求结果
状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。
状态码如 200 OK ,以 3 位数字和原因短语组成。
数字中的第一位指定了响应类别,后两位无分类。响应类别有以下 5 种。
|编号|类别|原因短语|
|---|||
|1XX|Informational(信息性状态码)|接受的请求正在处理|
|2XX|Success(成功状态码)|请求正常处理完毕|
|3XX|Redirection(重定向状态码)|需要进行附加操作以完成请求|
|4XX|Client Error(客户端错误状态码)|服务器无法处理请求|
|5XX|Server Error(服务器错误状态码)|服务器处理请求出错|
只要遵守状态码类别的定义,即使改变 RFC2616 中定义的状态码,或服务器端自行创建状态码都没问题。
HTTP 状态码就达很多,有60多种,但是常用的只有14个。
4.2 2XX成功
2XX的响应结果表明请求被正常处理了。
4.2.1 200 OK
- 表示从客户端发来的请求在服务器端被正常处理了。
在响应报文内,随状态码一起返回的信息会因方法的不同而发生改变。比如,使用 GET 方法时,对应请求资源的实体会作为响应返回;而使用 HEAD 方法时,对应请求资源的实体首部不随报文主体作为响应返回(即在响应中只返回首部,不会返回实体的主体部分)。
4.2.2 204 No Content
该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。比如,当从浏览器发出请求处理后,返回 204 响应,那么浏览器显示的页面不发生更新。
一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。
4.2.3 206 Partial Content
该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由Content-Range 指定范围的实体内容。
4.3 3XX 重定向
3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。
4.3.1 301 Moved Permanently
永久性重定向。该状态码表示请求的资源已被分配了新的 URI ,以后应使用资源现在所指的 URI 。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按 Location 首部字段提示的 URI 重新保存。
像下方给出的请求 URI ,当指定资源路径的最后忘记添加斜杠 “/” ,就会产生 301 状态码。
http://example.com/sample
4.3.2 302 Found
临时性重定向。该状态码表示请求的资源已被分配了新的 URI ,希望用户(本次)能使用新的 URI 访问。
和 301 Moved Permanently 状态码相似,但 302 状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的 URI 将来还有可能发生改变。比如,用户把 URI 保存成书签,但不会像 301 状态码出现时那样去更新书签,而是仍旧保留返回 302 状态码的页面对应的 URI 。
4.3.3 303 See Other
该状态码表示由于请求对应的资源存在着另一个 URI ,应使用 GET 方法定向获取请求的资源。
303 状态码和 302 Found 状态码有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资
源,这点与 302 状态码有区别。
比如,当使用 POST 方法访问 CGI 程序,其执行后的处理结果是希望客户端能以 GET 方法重定向到另一个
URI 上去时,返回 303 状态码。虽然 302 Found 状态码也可以实现相同的功能,但这里使用 303 状态码是
最理想的。
本书采用的是 HTTP/1.1 ,而许多 HTTP/1.1 版以前的浏览器不能正确理解 303 状态码。虽然 RFC 1945 和 RFC 2068 规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将 302 响应视为 303 响应,并且使用 GET 方式访问在 Location 中规定的 URI ,而无视原先请求的方法。所以作者说这里使用 303 是最理想的。
当 301 、 302 、 303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET ,并删除请求报文内的主体,之后请求会自动再次发送。
301 、 302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做。
4.3.4 304 Not Modified
该状态码表示客户端发送附带条件的请求 2 时,服务器端允许请求访问资源,但未满足条件的情况。 304 状态码返回时,不包含任何响应的主体部分。 304 虽然被划分在 3XX 类别中,但是和重定向没有关系。
4.3.5 307 Temporary Redirect
临时重定向。该状态码与 302 Found 有着相同的含义。尽管 302 标准禁止 POST 变换成 GET ,但实际使用
时大家并不遵守。
307 会遵照浏览器标准,不会从 POST 变成 GET 。但是,对于处理响应时的行为,每种浏览器有可能出现不同的情况。
4.4 4XX 客户端错误
4XX 的响应结果表明客户端是发生错误的原因所在。
4.4.1 400 Bad Request
该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。
4.4.2 401 Unauthorized
该状态码表示发送的请求需要有通过 HTTP 认证( BASIC 认证、 DIGEST 认证)的认证信息。另外若之前已进行过 1 次请求,则表示用户认证失败。
返回含有 401 的响应必须包含一个适用于被请求资源的 WWW-Authenticate 首部用以质询( challenge )用户信息。当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。
4.4.3 403 Forbidden
该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。
未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)等列举的情况都可能是发生 403 的原因。
4.4.4 404 Not Found
该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。
4.5 5XX 服务器错误
5XX 的响应结果表明服务器本身发生错误。
4.5.1 500 Internal Server Error
该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug 或某些临时的故障。
4.5.2 503 Service Unavailable
该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入 RetryAfter 首部字段再返回给客户端。
状态码和状况的不一致
不少返回的状态码响应都是错误的,但是用户可能察觉不到这点。比如 Web 应用程序内部发生错误,状态码依然返回 200 OK ,这种情况也经常遇到。
第 5 章与 HTTP 协作的Web服务器
5.1 用单台虚拟主机实现多个域名
HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站点。比如,提供 Web 托管服务( Web Hosting Service )的供应商,可以用一台服务器为多位客户服务,也可以以每位客户持有的域名运行各自不同的网站。这是因为利用了虚拟主机( Virtual Host ,又称虚拟服务器)的功能。
即使物理层面只有一台服务器,但只要使用虚拟主机的功能,则可以假想已具有多台服务器。
在互联网上,域名通过 DNS 服务映射到 IP 地址(域名解析)之后访问目标网站。可见,当请求发送到服务器时,已经是以 IP 地址形式访问了。
所以,如果一台服务器内托管了 www.tricorder.jp 和 www.hackr.jp 这两个域名,当收到请求时就需要弄清楚究竟要访问哪个域名。
在相同的 IP 地址下,由于虚拟主机可以寄存多个不同主机名和域名的 Web 网站,因此在发送 HTTP 请求时,必须在 Host 首部内完整指定主机名或域名的 URI 。
5.2 通信数据转发程序:代理、网关、隧道
HTTP 通信时,除客户端和服务器以外,还有一些用于通信数据转发的应用程序,例如代理、网关和隧道。它们可以配合服务器工作。
这些应用程序和服务器可以将请求转发给通信线路上的下一站服务器,并且能接收从那台服务器发送的响应再转发给客户端。
代理
: 代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端 “ 中间人 ” 的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。
网关
: 网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个网关。
隧道
: 隧道是在相隔甚远的客户端和服务器两者之间进行中转,并保持双方通信连接的应用程序。
代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求 URI ,会直接发送给前方持有资源的目标服务器。
持有资源实体的服务器被称为源服务器。从源服务器返回的响应经过代理服务器后再传给客户端。
在 HTTP 通信过程中,可级联多台代理服务器。请求和响应的转发会经过数台类似锁链一样连接起来的代理服务器。转发时,需要附加 Via 首部字段以标记出经过的主机信息。
使用代理服务器的理由有:利用缓存技术(稍后讲解)减少网络带宽的流量,组织内部针对特定网站的访问控制,以获取访问日志为主要目的,等等。
代理有多种使用方法,按两种基准分类。一种是是否使用缓存,另一种是是否会修改报文。
缓存代理
: 代理转发响应时,缓存代理( Caching Proxy )会预先将资源的副本(缓存)保存在代理服务器上。
当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回。
透明代理
: 转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理( Transparent Proxy )。反之,对报文内容进行加工的代理被称为非透明代理。
5.2.2 网关
网关的工作机制和代理十分相似。而网关能使通信线路上的服务器提供非 HTTP 协议服务。
利用网关能提高通信的安全性,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。比如,网关可以连接数据库,使用 SQL 语句查询数据。另外,在 Web 购物网站上进行信用卡结算时,网关可以和信用卡结算系统联动。
5.2.3 隧道
隧道可按要求建立起一条与其他服务器的通信线路,届时使用 SSL 等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信。
隧道本身不会去解析 HTTP 请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束。
5.3 保存资源的缓存
缓存是指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。
缓存服务器的优势在于利用缓存可避免多次从源服务器转发资源。因此客户端可就近从缓存服务器上获取资源,而源服务器也不必多次处理相同的请求了。
5.3.1 缓存的有效期限
即便缓存服务器内有缓存,也不能保证每次都会返回对同资源的请求。因为这关系到被缓存资源的有效性问题。
当遇上源服务器上的资源更新时,如果还是使用不变的缓存,那就会演变成返回更新前的 “ 旧 ” 资源了。
即使存在缓存,也会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断缓存失效,缓存服务器将会再次从源服务器上获取 “ 新 ” 资源。
5.3.2 客户端的缓存
缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以 Internet Explorer 程序为例,把客户端缓存称为临时网络文件( Temporary Internet File )。
浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。
另外,和缓存服务器相同的一点是,当判定缓存过期后,会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。
第 6 章 HTTP首部
HTTP 协议的请求和响应报文中必定包含 HTTP 首部,只是我们平时在使用 Web 的过程中感受不到它。
6.1 HTTP 报文首部
请求报文
报文首部 | 在客户端和服务器处理时起至关重要作用的信息几乎都在这边 |
---|---|
空行(CR+LF) | |
报文主体 | 所需要的用户和资源的信息都在这边 |
HTTP 协议的请求和响应报文中必定包含 HTTP 首部。首部内容为客户端和服务器分别处理请求和响应提供所需要的信息。对于客户端用户来说,这些信息中的大部分内容都无须亲自查看。
报文首部由几个字段构成。
HTTP 请求报文
: 在请求中,HTTP 报文由方法、URI 、HTTP 版本、 HTTP 首部字段等部分构成。
报文首部
请求行 | 方法、URI、HTTP版本 |
---|---|
请求首部字段 | HTTP首部字段 |
通用首部字段 | HTTP首部字段 |
实体首部字段 | HTTP首部字段 |
其他 |
GET / HTTP/1.1
Host: hackr.jp
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
If-Modified-Since: Fri, 31 Aug 2007 02:02:20 GMT
If-None-Match: "45bae1-16a-46d776ac"
Cache-Control: max-age=0
HTTP 响应报文
在响应中, HTTP 报文由 HTTP 版本、状态码(数字和原因短语)、 HTTP 首部字段 3 部分构成。
状态行 | 方法、URI、HTTP版本 |
---|---|
响应首部字段 | HTTP首部字段 |
通用首部字段 | HTTP首部字段 |
实体首部字段 | HTTP首部字段 |
其他 |
HTTP/1.1 304 Not Modified
Date: Thu, 07 Jun 2012 07:21:36 GMT
Server: Apache
Connection: close
Etag: "45bae1-16a-46d776ac"
6.2 HTTP 首部字段
6.2.1 HTTP 首部字段传递重要信息
HTTP 首部字段是构成 HTTP 报文的要素之一。在客户端与服务器之间以 HTTP 协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外重要信息的作用。
使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。
6.2.2 HTTP 首部字段结构
HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号 “:” 分隔。
首部字段名 : 字段值
另外,字段值对应单个 HTTP 首部字段可以有多个值,如下所示。
Keep-Alive: timeout=15, max=100
若 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 首部字段一览
通用首部字段
首部字段名 | 说明 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 逐跳首部、连接的管理 |
Date | 创建报文的日期时间 |
Pragma | 报文指令 |
Trailer | 报文末端的首部一览 |
Transfer-Encoding | 指定报文主体的传输编码方式 |
Upgrade | 升级为其他协议 |
Via | 代理服务器的相关信息 |
Warning | 错误通知 |
请求首部字段
Accept | 用户代理可处理的媒体类型 |
---|---|
Accept-Charset | 优先的字符集 |
Accept-Encoding | 优先的内容编码 |
Accept-Language | 优先的语言(自然语言) |
Authorization | Web认证信息 |
Expect | 期待服务器的特定行为 |
From | 用户的电子邮箱地址 |
Host | 请求资源所在服务器 |
If-Match | 比较实体标记( ETag ) |
If-Modified-Since | 比较资源的更新时间 |
If-None-Match | 比较实体标记(与 If-Match 相反) |
If-Range | 资源未更新时发送实体 Byte 的范围请求 |
If-Unmodified-Since | 比较资源的更新时间(与 If-Modified-Since 相反) |
Max-Forwards | 最大传输逐跳数 |
Proxy-Authorization | 代理服务器要求客户端的认证信息 |
Range | 实体的字节范围请求 |
Referer | 对请求中 URI 的原始获取方 |
TE | 传输编码的优先级 |
User-Agent | HTTP 客户端程序的信息 |
响应首部字段
Accept-Ranges | 是否接受字节范围请求 |
---|---|
Age | 推算资源创建经过时间 |
ETag | 资源的匹配信息 |
Location | 令客户端重定向至指定 URI |
Proxy-Authenticate | 代理服务器对客户端的认证信息 |
Retry-After | 对再次发起请求的时机要求 |
Server HTTP | 服务器的安装信息 |
Vary | 代理服务器缓存的管理信息 |
WWW-Authenticate | 服务器对客户端的认证信息 |
实体首部字段
Allow | 资源可支持的 HTTP 方法 |
---|---|
Content-Encoding | 实体主体适用的编码方式 |
Content-Language | 实体主体的自然语言 |
Content-Length | 实体主体的大小(单位:字节) |
Content-Location | 替代对应资源的 URI |
Content-MD5 | 实体主体的报文摘要 |
Content-Range | 实体主体的位置范围 |
Content-Type | 实体主体的媒体类型 |
Expires | 实体主体过期的日期时间 |
Last-Modified | 资源的最后修改日期时间 |
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 指令一览
缓存请求指令
指令 | 参数 | 说明 |
---|---|---|
no-cache | 无 | 强制向源服务器再次验证 |
no-store | 无 | 不缓存请求或响应的任何内容 |
max-age = [ 秒 ] | 必需 | 响应的最大 Age 值 |
max-stale( = [ 秒 ]) | 可省略 | 接收已过期的响应 |
min-fresh = [ 秒 ] | 必需 | 期望在指定时间内的响应仍有效 |
no-transform | 无 | 代理不可更改媒体类型 |
only-if-cached | 无 | 从缓存获取资源 |
cache-extension | - | 新指令标记( token ) |
缓存响应指令
指令 | 参数 | 说明 |
---|---|---|
public | 无 | 可向任意方提供响应的缓存 |
private | 可省略 | 仅向特定用户返回响应 |
no-cache | 可省略 | 缓存前必须先确认其有效性 |
no-store | 无 | 不缓存请求或响应的任何内容 |
no-transform | 无 | 代理不可更改媒体类型 |
must-revalidate | 无 | 可缓存但必须再向源服务器进行确认 |
proxy-revalidate | 无 | 要求中间缓存服务器对缓存的响应有效性再进行确认 |
max-age = [ 秒 ] | 必需 | 响应的最大 Age 值 |
s-maxage = [ 秒 ] | 必需 | 公共缓存服务器响应的最大 Age 值 |
cache-extension | - | 新指令标记( token ) |
表示是否能缓存的指令
public 指令
:
Cache-Control: public
当指定使用 public 指令时,则明确表明其他用户也可利用缓存。
private 指令
:
Cache-Control: private
当指定 private 指令后,响应只以特定的用户作为对象,这与 public 指令的行为相反。
缓存服务器会对该特定用户提供资源缓存的服务,对于其他用户发送过来的请求,代理服务器则不会返回缓存。
no-cache 指令
:
Cache-Control: no-cache
使用 no-cache 指令的目的是为了防止从缓存中返回过期的资源。
客户端发送的请求中如果包含 no-cache 指令,则表示客户端将不会接收缓存过的响应。于是, “ 中间 ” 的缓存服务器必须把客户端请求转发给源服务器。
如果服务器返回的响应中包含 no-cache 指令,那么缓存服务器不能对资源进行缓存。源服务器以后也将不再对缓存服务器请求中提出的资源有效性进行确认,且禁止其对响应资源进行缓存操作。
Cache-Control: no-cache=Location
由服务器返回的响应中,若报文首部字段 Cache-Control 中对 no-cache 字段名具体指定参数值,那么客户端在接收到这个被指定参数值的首部字段对应的响应报文后,就不能使用缓存。换言之,无参数值的首部字段可以使用缓存。只能在响应指令中指定该参数。
控制可执行缓存的对象的指令
no-store 指令
:
Cache-Control: no-store
当使用 no-store 指令 时,暗示请求(和对应的响应)或响应中包含机密信息。
从字面意思上很容易把 no-cache 误解成为不缓存,但事实上 no-cache 代表不缓存过期的资源,缓存会向源服务器进行有效期确认后处理资源,也许称为 do-not-serve-from-cache-without-revalidation 更合适。 no-store 才是真正地不进行缓存,请读本文档由Linux公社 www.linuxidc.com 整理者注意区别理解。
指定缓存期限和认证的指令
s-maxage 指令
:
Cache-Control: s-maxage=604800 (单位 :秒)
s-maxage 指令的功能和 max-age 指令的相同,它们的不同点是 s-maxage 指令只适用于供多位用户使用的公共缓存服务器。也就是说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。
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 秒的资源都无法作为响应返回了。
6.3.2 Connection
1、 控制不再转发给代理的首部字段
2、 管理持久连接
Connection: 不再转发的首部字段名
Connection:Upprade
在客户端发送请求和服务器返回响应内,使用 Connection 首部字段,可控制不再转发给代理的首部字段
Connection: close
HTTP/1.1 版本的默认连接都是持久连接。为此,客户端会在持久连接上连续发送请求。当服务器端想明确断开连接时,则指定 Connection 首部字段的值为 Close
Connection: Keep-Alive
HTTP/1.1 之前的 HTTP 版本的默认连接都是非持久连接。为此,如果想在旧版本的 HTTP 协议上维持持续连接,则需要指定 Connection 首部字段的值为 Keep-Alive
6.3.3 Date
首部字段 Date 表明创建 HTTP 报文的日期和时间。
HTTP/1.1 协议使用在 RFC1123 中规定的日期时间的格式
Date: Tue, 03 Jul 2012 04:40:59 GMT
HTTP 协议版本中使用在 RFC850 中定义的格式
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
该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源。
Cache-Control: no-cache
Pragma: no-cache
6.3.5 Trailer
首部字段 Trailer 会事先说明在报文主体后记录了哪些首部字段。该首部字段可应用在 HTTP/1.1 版本分块传输编码时。
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2012 04:40:56 GMT
Content-Type: text/html
...
Transfer-Encoding: chunked
Trailer: Expires
...( 报文主体 )...
0
Expires: Tue, 28 Sep 2004 23:59:59 GMT
以上用例中,指定首部字段 Trailer 的值为 Expires ,在报文主体之后(分块长度 0 之后)出现了首部字段Expires 。
6.3.6 Transfer-Encoding
首部字段 Transfer-Encoding 规定了传输报文主体时采用的编码方式
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2012 04:40:56 GMT
Cache-Control: public, max-age=604800
Content-Type: text/javascript; charset=utf-8
Expires: Tue, 10 Jul 2012 04:40:56 GMT
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Encoding: gzip
Transfer-Encoding: chunked
Connection: keep-alive
cf0 ←16 进制 (10 进制为 3312)
...3312 字节分块数据 ...
392 ←16 进制 (10 进制为 914)
...914 字节分块数据 ...
0
以上用例中,正如在首部字段 Transfer-Encoding 中指定的那样,有效使用分块传输编码,且分别被分成3312 字节和 914 字节大小的分块数据。
6.3.7 Upgrade
首部字段 Upgrade 用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。
Upgrade 首部字段产生作用的 Upgrade 对象仅限于客户端和邻接服务器之间。因此,使用首部字段 Upgrade 时,还需要额外指定 Connection:Upgrade 。
GET /index.html HTTP/1.1
Upgrade:TLS/1.0
Connection:Upgrade
HTTP/1.1 101 Switching Protocols
Upgrade:TLS/1.0,HTTP/1.1
Connection:Upgrade
首部字段 Upgrade 指定的值为 TLS/1.0 。请注意此处两个字段首部字段的对应关
系, Connection 的值被指定为 Upgrade 。 Upgrade 首部字段产生作用的 Upgrade 对象仅限于客户端和邻接
服务器之间。因此,使用首部字段 Upgrade 时,还需要额外指定 Connection:Upgrade 。
对于附有首部字段 Upgrade 的请求,服务器可用 101 Switching Protocols 状态码作为响应返回。
6.3.8 Via
使用首部字段 Via 是为了追踪客户端与服务器之间的请求和响应报文的传输路径。
报文经过代理或网关时,会先在首部字段 Via 中附加该服务器的信息,然后再进行转发。这个做法和traceroute 及电子邮件的 Received 首部的工作机制很类似。
首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。所以必须在经过代理时附加该首部字段内容。
GET /HTTP/1.1
GET /HTTP/1.1
Via: 1.0 gw.hackr.jp(Squid/3.1)
GET /HTTP/1.1
Via: 1.0 gw.hackr.jp(Squid/3.1),
1.1 a1.example.com(Squid/2.7)
Via 首部是为了追踪传输路径,所以经常会和 TRACE 方法一起使用。比如,代理服务器接收到由 TRACE 方法发送过来的请求(其中 Max-Forwards: 0 )时,代理服务器就不能再转发该请求了。这种情况下,代理服务器会将自身的信息附加到 Via 首部后,返回该请求的响应。
6.3.9 Warning
HTTP/1.1 的 Warning 首部是从 HTTP/1.0 的响应首部( Retry-After )演变过来的。该首部通常会告知用户一些与缓存相关的问题的警告。
Warning: 113 gw.hackr.jp:8080 "Heuristic expiration" Tue, 03 Jul 2012 05:09:44 GMT
Warning 首部的格式如下。最后的日期时间部分可省略。
Warning: [ 警告码 ][ 警告的主机 : 端口号 ]“[ 警告内容 ]”([ 日期时间 ])
HTTP/1.1 中定义了 7 种警告。
警告码 | 警告内容 | 说明 |
---|---|---|
110 | Response is stale (响应已过期) | 代理返回已过期的资源 |
111 | Revalidation failed (再验证失败) | 代理再验证资源有效性时失败(服务器无法到达等原因) |
112 | Disconnection operation (断开连接操作) | 代理与互联网连接被故意切断 |
113 | Heuristic expiration (试探性过期) | 响应的使用期超过 24 小时(有效缓存的设定时间大于 24 小时的情况下) |
199 | Miscellaneous warning (杂项警告) | 任意的警告内容 |
214 | Transformation applied (使用了转换) | 代理对内容编码或媒体类型等执行了某些处理时 |
299 | Miscellaneous persistent warning (持久杂项警告) | 任意的警告内容 |
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= 来额外表示权重值 1 ,用分号( ; )进行分隔。权重值 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 首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码。
gzip
由文件压缩程序 gzip ( GNU zip )生成的编码格式( RFC1952 ),采用 Lempel-Ziv 算法( LZ77 )及 32位循环冗余校验( Cyclic Redundancy Check ,通称 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 用来告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级。可一次指定多种自然语言集。
6.4.5 Authorization
1.客户端
GET /index.htm
2.服务器:该页面需要HTTP认证,把认证信息发给我
401 Unauthorized
WWW-Authenticate:Basic...
3.客户端
GET /index.htm
Authorization:Basic dWVub3NlbjpwYXNzd29yZA==
首部字段 Authorization 是用来告知服务器,用户代理的认证信息(证书值)。通常,想要通过服务器认证的用户代理会在接收到返回的 401 状态码响应后,把首部字段 Authorization 加入请求中。共用缓存在接收到含有 Authorization 首部字段的请求时的操作处理会略有差异。
6.4.6 Expect
Expect: 100-continue
客户端使用首部字段 Expect 来告知服务器,期望出现的某种特定行为。因服务器无法理解客户端的期望作出回应而发生错误时,会返回状态码 417 Expectation Failed 。
客户端可以利用该首部字段,写明所期望的扩展。虽然 HTTP/1.1 规范只定义了 100-continue (状态码 100Continue 之意)。
等待状态码 100 响应的客户端在发生请求时,需要指定 Expect:100-continue 。
6.4.7 From
From:info@hackr.jp
首部字段 From 用来告知服务器使用用户代理的用户的电子邮件地址。通常,其使用目的就是为了显示搜索引擎等用户代理的负责人的电子邮件联系方式。使用代理时,应尽可能包含 From 首部字段(但可能会因代理不同,将电子邮件地址记录在 User-Agent 首部字段内)。
6.4.8 Host
Host: www.hackr.jp
首部字段 Host 会告知服务器,请求的资源所处的互联网主机名和端口号。 Host 首部字段在 HTTP/1.1 规范内是唯一一个必须被包含在请求内的首部字段。
首部字段 Host 和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联,这是首部字段 Host 必须存在的意义。
请求被发送至服务器时,请求中的主机名会用 IP 地址直接替换解决。但如果这时,相同的 IP 地址下部署运行着多个域名,那么服务器就会无法理解究竟是哪个域名对应的请求。因此,就需要使用首部字段 Host 来明确指出请求的主机名。若服务器未设定主机名,那直接发送一个空值即可。