《图解HTTP》——上野 宣

图解HTTP

看完这本书并在此博客下摘录书中的部分知识以便回顾。

第一章 了解Web及网络基础

1.1 使用HTTP协议访问Web

Web使用一种名为HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器端等一系列运作流程。而协议是指规定的约定。可以说Web是建立在HTTP协议上通信的

1.2 HTTP的诞生

1.2.1 为知识共享而规划Web

CERN(欧洲核子研究组织)的蒂姆·博纳斯-李博士提出了一种能让远隔两地的研究者们共享知识的设想。

最初设想的基本理念是:借助多文档之间相互关联形成的超文本(HyperText),连成可相互参阅的WWW(World Wide Web,万维网)。

现在已提出了三项WWW的构建技术:分别是:把SGML(Standard Generalized Markup Language,标准通用标记语言)作为页面的文本标记语言的HTML(HyperText Markup Language,超文本标记语言);作为文档传递协议的HTTP指定文档所在地址的URL(Uniform Resource Locator,统一资源定位符)。

WWW这一名称,是Web浏览器当前用来浏览超文本的客户端应用程序时的名称。现在则用来表示这一系列的集合,也可以简称为Web。

1.2.2 Web成长时代

1990年11月CERN成功研发世界上第一台Web服务器和Web浏览器。

1992年日本第一个网站的主页上线了。

1993年1月,现代浏览器的祖先NCSA(National Center for Supercomputer Applications,美国国家超级计算机应用中心)研发的Mosaic问世了,它以in-line(内联)等形式显示HTML的图像,在图像方面出色的表现使它迅速在世界范围内流行起来。

1994年12月,网景通信公司发布了Netscape Navigator 1.0.

1995年微软公司发布Internet Explorer1.0和2.0,紧随其后的是先在已然成为Web服务器标准之一的Apache。

2004年,Mozilla基金会发布了Firefox浏览器。

随后,Chrome、Opera、Safari等浏览器纷纷诞生。

1.3 网络基础 TCP/IP

通常使用的网络(包括互联网)是在TCP/IP协议族的基础上运作的。而HTTP属于它的内部的一个子集

1.3.1 TCP/IP协议族

计算机和网络设备要相互通信,双方就必须基于相同的方法。比如,如何探测到通信目标、由哪一边发起通信、使用哪种语言进行通信、怎么结束通信等规则都需要事先确定。不同的硬件、操作系统之间的通信,所有的一切都需要一种规则。而我们就把这种规则称为协议(protocol)。

《图解HTTP》——上野 宣_第1张图片

1.3.2 TCP/IP的分层管理

TCP/IP 协议族里重要的一点就是分层。TCP/IP 协议族按层次分别分为以下 4 层:应用层传输层网络层数据链路层

把 TCP/IP 层次化是有好处的。比如,如果互联网只由一个协议统筹,某个地方需要改变设计时,就必须把所有部分整体替换掉。而分层之后只需把变动的层替换掉即可。把各层之间的接口部分规划好之后,每个层次内部的设计就能够自由改动了

值得一提的是,层次化之后,设计也变得相对简单了。处于应用层上的应用可以只考虑分派给自己的任务,而不需要弄清对方在地球上哪个地方、对方的传输路线是怎样的、是否能确保传输送达等问题。

应用层

应用层决定了向用户提供应用服务时通信的活动

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通信传输流

《图解HTTP》——上野 宣_第2张图片

发送端从应用层往下走,接收端则往应用层往上走

我们用 HTTP 举例来说明,首先作为发送端的客户端在应用层(HTTP 协议)发出一个想看某个 Web 页面的 HTTP 请求。

接着,为了传输方便,在传输层(TCP 协议)把从应用层处收到的数据(HTTP 请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。

在网络层(IP 协议),增加作为通信目的地的 MAC 地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。

接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。

当传输到应用层,才能算真正接收到由客户端发送过来的 HTTP 请求。

《图解HTTP》——上野 宣_第3张图片

发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息。反之,接收端在层与层传输数据时,每经过一层时会把对应的首部消去

这种把数据信息包装起来的做法称为封装(encapsulate)

1.4 与HTTP关系密切的协议:IP、TCP 和 DNS

1.4.1 负责传输的 IP 协议

按层次分,IP(Internet Protocol)网际协议位于网络层

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 地址

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 协议会再次以相同的顺序发送相同的数据包【这样才能确保可靠传输】。

《图解HTTP》——上野 宣_第4张图片

1.5 负责域名解析的DNS服务

DNS(Domain Name System)服务是和 HTTP 协议一样位于应用层的协议。它提供域名到 IP 地址之间的解析服务

用户通常使用主机名或域名来访问对方的计算机,而不是直接通过 IP 地址访问。因为与 IP 地址的一组纯数字相比,用字母配合数字的表示形式来指定计算机名更符合人类的记忆习惯。 但要让计算机去理解名称,相对而言就变得困难了。因为计算机更擅长处理一长串数字。【DNS的起源】

为了解决上述的问题,DNS 服务应运而生。DNS 协议提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务。

在这里插入图片描述

1.6 各种协议与HTTP协议的关系

《图解HTTP》——上野 宣_第5张图片

1.7 URI和URL

与 URI(统一资源标识符)相比,我们更熟悉 URL(Uniform Resource Locator,统一资源定位符)。

URI 是 Uniform Resource Identifier 的缩写。RFC2396 分别对这 3 个单词进行了如下定义。

URI 是由某个协议方案表示的资源的定位标识符。协议方案是指访问资源所使用的协议类型名称。

URI 用字符串标识某一互联网资源,而 URL 表示资源的地点(互联网上所处的位置)。可见 URL 是 URI 的子集

URI格式如下:
《图解HTTP》——上野 宣_第6张图片

第二章 简单的HTTP协议

2.1 HTTP协议用于客户端和服务器端之间的通信

应用 HTTP 协议时,必定是一端担任客户端角色,另一端担任服务器端角色

2.2 通过请求和响应的交换达成通信

《图解HTTP》——上野 宣_第7张图片

下面则是从客户端发送给某个 HTTP 服务器端的请求报文中的内容。

GET /index.htm HTTP/1.1 【方法 资源对象 版本号】
Host: hackr.jp

综合来看,这段请求内容的意思是:请求访问某台 HTTP 服务器上的 /index.htm 页面资源。

请求报文是由请求方法、请求 URI、协议版本、可选的请求首部字段和内容实体构成的。

请求报文的构成:

// 【方法 URL 协议版本】
POST /form/entry HTTP/1.1
// 【请求首部字段】
Host: hackr.jp
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 16
// 【内容实体】
name=ueno&age=37

响应报文基本上由协议版本、状态码(表示请求成功或失败的数字代码)、用以解释状态码的原因短语可选的响应首部字段以及实体主体构成。稍后我们会对这些内容进行详细说明。

响应报文的构成:

// 【协议版本 状态码 状态码的原因短语】
HTTP/1.1 200 OK
// 【响应首部字段】
Date: Tue, 10 Jul 2012 06:50:15 GML
Content-Length: 362
Content-Type: text/html
// 【主体】
<html>
...

2.3 HTTP是不保存状态的协议

HTTP 是一种不保存状态,即无状态(stateless)协议。HTTP 协议自身不对请求和响应之间的通信状态进行保存。也就是说在 HTTP 这个级别,协议对于发送过的请求或响应都不做持久化处理

《图解HTTP》——上野 宣_第8张图片

使用 HTTP 协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。

可是,随着 Web 的不断发展,因无状态而导致业务处理变得棘手的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能够掌握是谁送出的请求,需要保存用户的状态。【Cookie的起源】 HTTP/1.1 虽然是无状态协议,但为了实现期望的保持状态功能,于是引入了 Cookie 技术。有了 Cookie 再用 HTTP 协议通信,就可以管理状态了。

2.4 告知服务器意图的HTTP方法

GET:获取资源

POST:传输实体主体

虽然用 GET 方法也可以传输实体的主体,但一般不用 GET 方法进行传输,而是用 POST 方法。虽说 POST 的功能与 GET 很相似,但 POST 的主要目的并不是获取响应的主体内容。

PUT:传输文件

方法用来传输文件。就像 FTP 协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置。

HEAD:获得报文首部

HEAD 方法和 GET 方法一样,只是不返回报文主体部分。用于确认 URI 的有效性及资源更新的日期时间等。

DELETE:删除文件

DELETE 方法用来删除文件,是与 PUT 相反的方法。DELETE 方法按请求 URI 删除指定的资源。

OPTIONS:询问支持的方法

OPTIONS 方法用来查询针对请求 URI 指定的资源支持的方法。

TRACE:追踪路径

TRACE 方法是让 Web 服务器端将之前的请求通信环回给客户端的方法。

发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器端就将该数字减 1,当数值刚好减到 0 时,就停止继续传输,最后接收到请求的服务器端则返回状态码 200 OK 的响应。

客户端通过 TRACE 方法可以查询发送出去的请求是怎样被加工修改 / 篡改的。这是因为,请求想要连接到源目标服务器可能会通过代理中转,TRACE 方法就是用来确认连接过程中发生的一系列操作。

但是,TRACE 方法本来就不怎么常用,再加上它容易引发 XST(Cross-Site Tracing,跨站追踪)攻击,通常就更不会用到了。

CONNECT:要求用隧道协议连接代理

CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信。主要使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。

CONNECT 代理服务器名:端口号 HTTP协议

《图解HTTP》——上野 宣_第9张图片

使用CONNECT方法请求响应的例子

请求			CONNETC proxy.hackr.jp:8080 HTTP/1.1
			  Host: proxy.hackr.jp
响应			HTTP/1.1 200 OK(之后进入网络隧道)

HTTP/1.0 和 HTTP/1.1 支持的方法

方法 说明 支持的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.5 持久连接节省通信量

HTTP 协议的初始版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。

以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大问题。可随着 HTTP 的普及,文档中包含大量图片的情况多了起来,因此,每次请求都会造成无谓的TCP连接建立和断开,增加通信量的开销。

2.5.1 持久连接

为解决上述 TCP 连接的问题,HTTP/1.1 和一部分的 HTTP/1.0 想出了持久连接(HTTP Persistent Connections,也称为 HTTP keep-alive 或 HTTP connection reuse)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

《图解HTTP》——上野 宣_第10张图片

持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外,减少开销的那部分时间,使 HTTP 请求和响应能够更早地结束,这样 Web 页面的显示速度也就相应提高了

2.5.2 管线化

持久连接使得多数请求以管线化(pipelining)方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,不用等待响应亦可直接发送下一个请求。

这样就能够做到同时并行发送多个请求,而不需要一个接一个地等待响应了。

《图解HTTP》——上野 宣_第11张图片

2.6 使用 Cookie 的状态管理

假设要求登录认证的 Web 页面本身无法进行状态的管理(不记录已登录的状态),那么每次跳转新页面不是要再次登录,就是要在每次请求报文中附加参数来管理登录状态。【HTTP是无状态协议,不对之前发生过的请求和响应的状态进行管理,也就是说无法根据之前的状态进行本次的请求处理】。

保留无状态协议这个特征的同时又要解决类似的矛盾问题,于是引入了 Cookie 技术。Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。

Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。 服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。【Cookie原理

使用Cookie的HTTP 请求报文和响应报文的内容示例如下:

1.请求报文(没有Cookie 信息状态)的请求

GET /reader/ HTTP/1.1
Host: hacker.jp
*首部字段内没有Cookie的相关信息

2.响应报文(服务器端生成Cookie 信息)

HTTP/1.1 200 OK
DateL 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

第三章、HTTP报文内的HTTP信息

3.1 HTTP报文

用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。

3.2 请求报文及响应报文的结构

《图解HTTP》——上野 宣_第12张图片

**请求行:**包含用于请求的方法,请求 URI 和 HTTP 版本。

**状态行:**包含表明响应结果的状态码,原因短语和 HTTP 版本。

**首部字段:**包含表示请求和响应的各种条件和属性的各类首部。

一般有 4 种首部,分别是:通用首部、请求首部、响应首部和实体首部。

**其他:**可能包含 HTTP 的 RFC 里未定义的首部(Cookie 等)。

3.3 编码提升传输速率

HTTP 在传输数据时可以按照数据原貌直接传输,但也可以在传输过程中通过编码提升传输速率

3.3.1 报文主体和实体主体的差异

  • 报文(message)

HTTP 通信中的基本单位,由 8 位组字节流(octet sequence,其中 octet 为 8 个比特)组成,通过 HTTP 通信传输。

  • 实体(entity)

作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。

HTTP 报文的主体用于传输请求或响应的实体主体。

**通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。**请理解两者的差异。

3.3.2 压缩传输的内容编码

《图解HTTP》——上野 宣_第13张图片

图:内容编码

常用的内容编码有以下几种。

  • gzip(GNU zip)
  • compress(UNIX 系统的标准压缩)
  • deflate(zlib)
  • identity(不进行编码)

3.3.3 分割发送的分块传输编码

在 HTTP 通信过程中,请求的编码实体资源尚未全部传输完成之前,浏览器无法显示请求页面。在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。 这种把实体主体分块的功能称为分块传输编码(Chunked Transfer Coding)。

3.3.4 发送多种数据的多部分对象集合

《图解HTTP》——上野 宣_第14张图片

发送邮件时,我们可以在邮件里写入文字并添加多份附件。这是因为采用了 **MIME(Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)机制,它允许邮件处理文本、图片、视频等多个不同类型的数据。例如,图片等二进制数据以 ASCII 码字符串编码的方式指明,就是利用 MIME 来描述标记数据类型。而在 MIME 扩展中会使用一种称为多部分对象集合(Multipart)**的方法,来容纳多份不同类型的数据。

相应地,HTTP 协议中也采纳了多部分对象集合,发送的一份报文主体内可含有多类型实体。通常是在图片或文本文件等上传时使用。 多部分对象集合包含的对象如下。

  • multipart/form-data:在Web表单文件上传时使用
  • multipart/byteranges:状态码206(Partial Content,部分内容)响应报文包含了多个范围的内容时使用。

使用 boundary 字符串来划分多部分对象集合指明的各类实体。在 boundary 字符串指定的各个实体的起始行之前插入“–”标记(例如:–AaB03x、–THIS_STRING_SEPARATES),而在多部分对象集合对应的字符串的最后插入“–”标记(例如:–AaB03x–、–THIS_STRING_SEPARATES–)作为结束。

3.3.5 获取部分内容的范围请求

《图解HTTP》——上野 宣_第15张图片

执行范围请求时,可以用到首部字段 Range 来指定资源的 byte 范围。

针对范围请求,响应会返回状态码为 206 Partial Content 的响应报文。另外,对于多重范围的范围请求,响应会在首部字段 Content-Type 标明 multipart/byteranges 后返回响应报文。

3.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): 是服务器驱动和客户端驱动的结合体,是由服务器端和客户端各自进行内容协商的一种方法。

第四章、返回结果的HTTP的状态码

4.1 状态码的类别

类别 原因短语
1XX Informational(信息性状态码) 接收的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出错

4.2 2XX 成功

4.2.1 200 OK

客户端发来的请求在服务器端被正常处理了

4.2.2 204 No Content

《图解HTTP》——上野 宣_第16张图片

该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。比如,当从浏览器发出请求处理后,返回 204 响应,那么浏览器显示的页面不发生更新。

一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用【服务端不需要返回资源】。

4.2.3 206 Partial Content

《图解HTTP》——上野 宣_第17张图片

该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由 Content-Range 指定范围的实体内容【服务端返回部分资源】。

4.3 3XX 重定向【不太理解】

3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。

4.3.1 301 Moved Permanently

《图解HTTP》——上野 宣_第18张图片

永久性重定向。该状态码表示请求的资源已被分配了新的 URI,以后应使用资源现在所指的 URI。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按 Location 首部字段提示的 URI 重新保存。

4.3.2 302 Found

《图解HTTP》——上野 宣_第19张图片

临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。 和 301 Moved Permanently 状态码相似,但 302 状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的 URI 将来还有可能发生改变。比如,用户把 URI 保存成书签,但不会像 301 状态码出现时那样去更新书签,而是仍旧保留返回 302 状态码的页面对应的 URI。

4.3.3 303 See Other

该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。

4.3.4 304 Not Modified

《图解HTTP》——上野 宣_第20张图片

该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。304 状态码返回时,不包含任何响应的主体部分。304 虽然被划分在 3XX 类别中,但是和重定向没有关系。

附带条件的请求是指采用 GET 方法的请求报文中包含 If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since 中任一首部。

4.4 4XX 客户端错误

4XX 的响应结果表明客户端是发生错误的原因所在。

4.4.1 400 Bad Request

《图解HTTP》——上野 宣_第21张图片

该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。

4.4.2 401 Unauthorized

《图解HTTP》——上野 宣_第22张图片

该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。另外若之前已进行过 1 次请求,则表示用 户认证失败。 返回含有 401 的响应必须包含一个适用于被请求资源的 WWW-Authenticate 首部用以质询(challenge)用户信息

当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。

4.4.3 404 Not Found

该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。

4.5 5XX 服务器错误

5XX 的响应结果表明服务器本身发生错误。

4.5.1 500 Internal Server Error

《图解HTTP》——上野 宣_第23张图片

该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug 或某些临时的故障

4.5.2 503 Service Unavailable

《图解HTTP》——上野 宣_第24张图片

该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入 RetryAfter 首部字段再返回给客户端。

状态码和状况的不一致:不少返回的状态码响应都是错误的,但是用户可能察觉不到这点。比如 Web 应用程序内部发生错误,状态码依然返回 200 OK,这种情况也经常遇到。

第五章、与HTTP协作的Web服务器

一台Web服务器可搭建多个独立域名的Web网站,也可作为通信路径上的中转服务器提升传输效率。

5.1 用单台虚拟主机实现多个域名

HTTP/1.1 规范允许一台 HTTP 服务器搭建多个 Web 站点。比如,提供 Web 托管服务(Web Hosting Service)的供应商,可以用一台服务器为多位客户服务,也可以以每位客户持有的域名运行各自不同的网站。这是因为利用了**虚拟主机(Virtual Host,又称虚拟服务器)**的功能。

即使物理层面只有一台服务器,但只要使用虚拟主机的功能,则可以假想已具有多台服务器。

《图解HTTP》——上野 宣_第25张图片
《图解HTTP》——上野 宣_第26张图片

5.2 通信数据转发程序:代理、网关、隧道

HTTP 通信时,除客户端和服务器以外,还有一些用于通信数据转发的应用程序,例如代理、网关和隧道。它们可以配合服务器工作。

这些应用程序和服务器可以将请求转发给通信线路上的下一站服务器,并且能接收从那台服务器发送的响应再转发给客户端。

代理

代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“中间人”的角色,接收由客户端发送的请求并转发给服务器,同时也接收服务器返回的响应并转发给客户端。

网关

网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个网关。

隧道

隧道是在相隔甚远的客户端和服务器两者之间进行中转,并保持双方通信连接的应用程序。

5.2.1 代理

《图解HTTP》——上野 宣_第27张图片

代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求 URI,会直接发送给前方持有资源的目标服务器。 持有资源实体的服务器被称为源服务器。从源服务器返回的响应经过代理服务器后再传给客户端。

在 HTTP 通信过程中,可级联多台代理服务器。请求和响应的转发会经过数台类似锁链一样连接起来的代理服务器。转发时,需要附加 Via 首部字段以标记出经过的主机信息

《图解HTTP》——上野 宣_第28张图片

使用代理服务器的理由有:

  1. 利用缓存技术减少网络带宽的流量。
  2. 组织内部针对特定网站的访问控制
  3. 获取访问日志为主要目的。

代理有多种使用方法,按两种基准分类:

  • 是否使用缓存
  • 是否会修改报文

缓存代理

代理转发响应时,缓存代理(Caching Proxy)会预先将资源的副本(缓存)保存在代理服务器上

当代理再次接收到对相同资源的请求时,就可以不从服务器那里获取资源,而是将之前缓存的资源作为响应返回。

透明代理

转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理(Transparent Proxy)。反之,对报文内容进行加工的代理被称为非透明代理。

5.2.2 网关

网关的工作机制和代理十分相似。而网关能使通信线路上的服务器提供非HTTP协议服务【与代理的主要差异】。

《图解HTTP》——上野 宣_第29张图片

利用网关能提高通信的安全性,因为可以在客户端与网关之间的通信线路上加密以确保连接的安全。比如,网关可以连接数据库,使用SQL语句查询数据。另外,在Web购物网站上进行信用卡结算时,网关可以和信用卡结算系统联动。

5.2.3 隧道

隧道可按要求建立起一条与服务器的通信线路,届时使用 SSL 等加密手段进行通信。隧道的目的是确保客户端能与服务器进行安全的通信

隧道本身不会去解析HTTP请求。也就是说,请求保持原样中转给之后的服务器。隧道会在通信双方断开连接时结束

《图解HTTP》——上野 宣_第30张图片

通过隧道的传输,可以和远距离的服务器安全通信。隧道本身是透明的,客户端不用在意隧道的存在。

5.3 保存资源的缓存

缓存是指代理服务器客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。

《图解HTTP》——上野 宣_第31张图片

缓存服务器是代理服务器的一种,并归类在缓存代理类型中。换句话说,当代理转发从服务器返回的响应时,代理服务器将会保存一份资源的副本。

5.3.1 客户端的缓存

缓存不仅可以存在于缓存服务器内,还可以存在客户端浏览器中。以 Internet Explorer 程序为例,把客户端缓存称为临时网络文件(Temporary Internet File)。

浏览器缓存如果有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。

另外,和缓存服务器相同的一点是,当判定缓存过期后,会向源服务器确认资源的有效性。若判断浏览器缓存失效,浏览器会再次请求新资源。

第六章、HTTP首部

6.1 HTTP报文首部

HTTP报文的结构:
《图解HTTP》——上野 宣_第32张图片

报文首部的内容为客户端和服务器分别处理请求和响应提供所需要的信息。对于客户端用户来说,这些信息大部分都无需亲自查看。

报文主体的内容往往包括所需要的用户和资源的信息。

6.2 HTTP首部字段

6.2.1 4种HTTP首部字段类型

HTTP首部字段根据实际用途被分为以下4中类型:

  • 通用首部字段(Genera Header Fields):请求报文和响应报文双方都会使用的首部。
  • 请求首部字段(Request Header Fields):从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
  • 响应首部字段(Response Header Fields):从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
  • 实体首部字段(Entity Header Fields):针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。

6.2.2 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.3 非HTTP/1.1首部字段

在HTTP协议通信交互中使用到的首部字段,不限于RFC2616中定义的47种首部字段。还有Cookie、Set-Cookies和Content-Disposition等在其他RFC中定义的首部字段,它们的使用频率也很高。

这些非正式的首部字段统一归纳在 RFC4229 HTTP Header Field Registrations 中。

6.2.4 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 通用首部字段

《图解HTTP》——上野 宣_第33张图片

浏览器缓存相关博客:作为面试官,我希望你知道这些浏览器缓存知识

6.3.1 Cache-Control

通过指定首部字段Cache-Control的指令,就能操作缓存的工作机制【控制缓存的行为,指挥缓存服务器】。

《图解HTTP》——上野 宣_第34张图片

Cache-Control指令的参数是可选的,多个指令之间通过","分隔,并且可用于请求及响应时。

Cache-Control: private, max-age=0, no-cache

可用的指令按请求和响应分类如下所示:

缓存请求指令

指令 参数 说明
no-cache 强制向源服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age = [秒] 必须 响应的最大Age值
max-stale( = [ 秒]) 可省略 接收已过期的响应【指示缓存资源,即使过期也照常接收,如果未指示参数值,无法经过多久,客户端都会接收响应,如果指定了具体数值,那么即使过期,只要仍处于max-stale指定的时间内,仍然会被客户端接收】
min-fresh = [ 秒] 必需 期望在指定时间内的响应仍有效【要求缓存服务器返回还未过指定时间的缓存资源,如指定min-fresh=60,过了60秒的资源都无法作为响应返回了】
no-transform 代理不可更改媒体类型
only-if-cached 从缓存获取资源【客户端仅在缓存服务器本地缓存目标资源的情况下才会要求其返回,换言之,该指令要求缓存服务器不重新加载响应,也不会再次确认资源的有效性。】
cache-extension - 新指令标记(token)

缓存响应指令

指令 参数 说明
public 可向任意方提供响应的缓存【什么代理啊,客户端啊都能缓存】
private 可省略 仅向特定用户返回响应【只有客户端能缓存,与public相反】
no-cache 可省略 缓存前必须先确认其有效性【不缓存过期的资源,不用从字面意思上误解为不缓存】
no-store 不缓存请求或响应的任何内容【不进行缓存,注意和no-cache区分】
no-transform 代理不可更改媒体类型【规定无论是在请求还是响应中,缓存都不能改变实体主体的媒体类型,这样做可防止缓存或代理压缩图片等类似操作】
must-revalidate 可缓存但必须再向源服务器进行确认【代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效】
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认【要求所有的缓存服务器在接收到客户端带有该指令的返回响应之前,必需再次验证缓存的有效性】
max-age = [ 秒] 必需 响应的最大Age值【和s-maxage功能相同,但s-maxage只适用于供多位用户使用的公共缓存服务器(一般指代理),对于向同一用户重复返回响应的服务器来说,s-maxage没有任何作用】【大白话就是缓存的最大有效时间】
s-maxage = [ 秒] 必需 公共缓存服务器【一般指代理】响应的最大Age值【指定缓存期限和认证的指令】,使用后会直接忽略对Expires首部字段及max-age指令的处理
cache-extension - 新指令标记(token)

no-cache指令

《图解HTTP》——上野 宣_第35张图片

使用no-cache指令的目的是为了防止从缓存中返回过期的资源

使用 no-cache 指令的目的是为了防止从缓存中返回过期的资源。 客户端发送的请求中如果包含 no-cache 指令,则表示客户端将不会接收缓存过的响应。于是,“中间”的缓存服务器必须把客户端请求转发给源服务器。

如果服务器返回的响应中包含 no-cache 指令,那么缓存服务器不能对资源进行缓存。源服务器以后也将不再对缓存服务器请求中提出的资源有效性进行确认,且禁止其对响应资源进行缓存操作。

Cache-Control: no-cache=Location

由服务器返回的响应中,若报文首部字段 Cache-Control 中对 no-cache 字段名具体指定参数值,那么客户端在接收到这个被指定参数值的首部字段对应的响应报文后,就不能使用缓存。换言之,无参数值的首部字段可以使用缓存。只能在响应指令中指定该参数。

6.3.2 Connection

Connection首部字段具备如下两个作用:

  • 控制不再转发给代理的首部字段
  • 管理持久连接

《图解HTTP》——上野 宣_第36张图片

在客户端发送请求和服务器返回响应内,使用Connection首部字段,可控制不再转发给代理的首部字段(即Hop-by-hop首部,Upgrade就是Hop-by-hop首部)。

《图解HTTP》——上野 宣_第37张图片

HTTP/1.1 版本的默认连接都是持久连接。为此,客户端会在持久连接上连续发送请求。当服务器端想明确断开连接时,则指定 Connection 首部字段的值为 Close

HTTP/1.1 之前的 HTTP 版本的默认连接都是非持久连接。为此,如果想在旧版本的 HTTP 协议上维持持续连接,则需要指定 Connection 首部字段的值为 Keep-Alive。

如上图①所示,客户端发送请求给服务器时,服务器端会像上图②那样加上首部字段 Keep-Alive 及首部字段 Connection 后返回响应。

6.3.3 Date

首部字段Date表明创建HTTP报文的日期和时间。

6.3.4 Pragma

Pragma: no-cache:跟Cache-Control: no-cache相同,Pragma: no-cache兼容http 1.0Cache-Control: no-cache是http 1.1提供的

因此,Pragma: no-cache可以应用到http 1.0 和http 1.1,而Cache-Control: no-cache只能应用于http 1.1.

该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源

所有的中间服务器如果都能以 HTTP/1.1 为基准,那直接采用 Cache-Control: no-cache 指定缓存的处理方式是最为理想的。但要整体掌握全部中间服务器使用的 HTTP 协议版本却是不现实的。因此,发送的请求会同时含有下面两个首部字段。

Cache-Control: no-cache
Pragma: no-cache

6.3.5 Trailer

《图解HTTP》——上野 宣_第38张图片

首部字段 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》——上野 宣_第39张图片

HTTP/1.1 的传输编码方式仅对分块传输编码有效

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

用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信,其参数值可以用来指定一个完全不同的通信协议。

《图解HTTP》——上野 宣_第40张图片

上图用例中,首部字段 Upgrade 指定的值为 TLS/1.0。请注意此处两个字段首部字段的对应关系,Connection 的值被指定为 Upgrade。Upgrade 首部字段产生作用的 Upgrade 对象仅限于客户端和邻接服务器之间。因此,使用首部字段 Upgrade 时,还需要额外指定 Connection:Upgrade。

对于附有首部字段 Upgrade 的请求,服务器可用 101 Switching Protocols 状态码作为响应返回。

6.3.8 Via

使用首部字段 Via 是为了追踪客户端与服务器之间的请求和响应报文的传输路径

报文经过代理或网关时,会先在首部字段 Via 中附加该服务器的信息,然后再进行转发

首部字段 Via 不仅用于追踪报文的转发,还可避免请求回环的发生。所以必须在经过代理时附加该首部字段内容。

《图解HTTP》——上野 宣_第41张图片

上图用例中,在经过代理服务器 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: 113 gw.hackr.jp:8080 "Heuristic expiration" Tue, 03 Jul 2012 05:09:44 GMT

Warning 首部的格式如下。最后的日期时间部分可省略。

Warning: [警告码] [警告的主机:端口号][警告内容]([日期时间])

6.4 请求首部字段

6.4.1 Accept

Accept 首部字段可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。可使用 type/subtype 这种形式,一次指定多种媒体类型。

《图解HTTP》——上野 宣_第42张图片

若想要给显示的媒体类型增加优先级,则使用 q= 来额外表示权重值 1,用分号(;)进行分隔。权重值 q 的范围是 0~1(可精确到小数点后 3 位),且 1 为最大值。不指定权重 q 值时,默认权重为 q=1.0。

当服务器提供多种内容时,将会首先返回权重值最高的媒体类型。

6.4.2 Accept-Charset

Accept-Charset 首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。另外,可一次性指定多种字符集。与首部字段 Accept 相同的是可用权重 q 值来表示相对优先级

Accept-Charset: iso-8859-5, unicode-1-1;q=0.8

6.4.3 Accept-Encoding

Accept-Encoding 首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码。

《图解HTTP》——上野 宣_第43张图片

下面试举出几个内容编码的例子:

  • 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:不执行压缩或不会变化的默认编码格式

采用权重 q 值来表示相对优先级,这点与首部字段 Accept 相同。另外,也可使用星号(*)作为通配符,指定任意的编码格式。

6.4.4 Accept-Language

首部字段 Accept-Language 用来告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级。可一次指定多种自然语言集。

和 Accept 首部字段一样,按权重值 q 来表示相对优先级。

6.4.5 Authorization

首部字段 Authorization 是用来告知服务器,用户代理的认证信息(证书值)

通常,想要通过服务器认证的用户代理会在接收到返回的 401 状态码响应后,把首部字段 Authorization 加入请求中。

《图解HTTP》——上野 宣_第44张图片

6.4.6 Expect

客户端使用首部字段 Expect 来告知服务器,期望出现的某种特定行为。因服务器无法理解客户端的期望作出回应而发生错误时,会返回状态码 417 Expectation Failed。

6.4.7 From

首部字段 From 用来告知服务器使用用户代理的用户的电子邮件地址。通常,其使用目的就是为了显示搜索引擎等用户代理的负责人的电子邮件联系方式。使用代理时,应尽可能包含 From 首部字段(但可能会因代理不同,将电子邮件地址记录在 User-Agent 首部字段内)。

6.4.8 Host

《图解HTTP》——上野 宣_第45张图片

首部字段 Host 会告知服务器,请求的资源所处的互联网主机名和端口号

Host 首部字段在 HTTP/1.1 规范内是唯一一个必须被包含在请求内的首部字段

首部字段 Host 和以单台服务器分配多个域名的虚拟主机的工作机制有很密切的关联,这是首部字段 Host 必须存在的意义。

请求被发送至服务器时,请求中的主机名会用 IP 地址直接替换解决。但如果这时,相同的 IP 地址下部署运行着多个域名,那么服务器就会无法理解究竟是哪个域名对应的请求。因此,就需要使用首部字段 Host 来明确指出请求的主机名【Host请求首部的意义】。

若服务器未设定主机名,那直接发送一个空值即可。如下所示。

Host: 

6.4.9 If-Match

形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求

《图解HTTP》——上野 宣_第46张图片

举例:只有当If-Match的字段值跟ETag值匹配一致时,服务器才会接受请求,如下图:

《图解HTTP》——上野 宣_第47张图片

6.4.10 If-Modified-Since

如果在 If-Modified-Since 字段指定的日期时间后,资源发生了更新,服务器会接受请求,如下图:

《图解HTTP》——上野 宣_第48张图片

If-Modified-Since 用于确认代理或客户端拥有的本地资源的有效性。获取资源的更新日期时间,可通过确认首部字段 Last-Modified 来确定。

6.4.11 If-None-Match

只有在 If-None-Match 的字段值与 ETag 值不一致时,可处理该请求。与 If-Match 首部字段的作用相反。如下图:

《图解HTTP》——上野 宣_第49张图片

6.4.12 If-Range

首部字段 If-Range 属于附带条件之一。它告知服务器若指定的 If-Range 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。如下图:

《图解HTTP》——上野 宣_第50张图片

6.4.13 If-Unmodified-Since

首部字段 If-Unmodified-Since 和首部字段 If-Modified-Since 的作用相反。它的作用的是告知服务器,指定的请求资源只有在字段值内指定的日期时间之后,未发生更新的情况下,才能处理请求。如果在指定日期时间后发生了更新,则以状态码 412 Precondition Failed 作为响应返回。

6.4.14 Max-Forwords

《图解HTTP》——上野 宣_第51张图片

通过 TRACE 方法或 OPTIONS【预检请求】 方法,发送包含首部字段 Max-Forwards 的请求时,该字段以十进制整数形式指定可经过的服务器最大数目。服务器在往下一个服务器转发请求之前,Max-Forwards

使用 HTTP 协议通信时,请求可能会经过代理等多台服务器。途中,如果代理服务器由于某些原因导致请求转发失败,客户端也就等不到服务器返回的响应了。对此,我们无从可知。 **可以灵活使用首部字段 Max-Forwards,针对以上问题产生的原因展开调查。**由于当 Max-Forwards 字段值为 0 时,服务器就会立即返回响应,由此我们至少可以对以那台服务器为终点的传输路径的通信状况有所把握。

6.4.15 Proxy-Authorization

接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段 Proxy-Authorization 的请求,以告知服务器认证所需要的信息。例子如下:

Proxy-Authorization: Basic dGlwOjkpNLAGfFY5

这个行为是与客户端和服务器之间的 HTTP 访问认证相类似的,不同之处在于,认证行为发生在客户端与代理之间。客户端与服务器之间的认证,使用首部字段 Authorization 可起到相同作用。有关

6.4.16 Range

对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围。上面的示例表示请求获取从第

Range: bytes=5001-10000

即可告知服务器资源的指定范围。上面的示例表示请求获取从第 5001 字节至第 10000 字节的资源。

接收到附带 Range 首部字段请求的服务器,会在处理请求之后返回状态码为 206 Partial Content 的响应。无法处理该范围请求时,则会返回状态码 200 OK 的响应及全部资源。

6.4.17 Referer

首部字段 Referer 会告知服务器请求的原始资源的 URI。

客户端一般都会发送 Referer 首部字段给服务器。但当直接在浏览器的地址栏输入 URI,或出于安全性的考虑时,也可以不发送该首部字段。

因为原始资源的 URI 中的查询字符串可能含有 ID 和密码等保密信息,要是写进 Referer 转发给其他服务器,则有可能导致保密信息的泄露。

6.4.18 TE

首部字段 TE 会告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相像,但是用于传输编码,而Accept-Encoding用于告知服务器用户代理支持的内容编码以及内容编码优先级

TE: gzip, deflate;q=0.5

6.4.19 User-Agent

首部字段 User-Agent 会将创建请求的浏览器和用户代理名称等信息传达给服务器

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36

由网络爬虫发起请求时,有可能会在字段内添加爬虫作者的电子邮件地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称。

6.5 响应首部字段

6.5.1 Accept-Ranges

首部字段 Accept-Ranges 是用来告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源。

可指定的字段值有两种,可处理范围请求时指定其为 bytes,反之则指定其为 none
《图解HTTP》——上野 宣_第52张图片

6.5.2 Age

首部字段 Age 能告知客户端,源服务器在多久前创建了响应。字段值的单位为秒。

《图解HTTP》——上野 宣_第53张图片

若创建该响应的服务器是缓存服务器,Age 值是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须加上首部字段 Age。

6.5.3 ETag

首部字段 ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag 值。

另外,当资源更新时,ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。

《图解HTTP》——上野 宣_第54张图片

资源被缓存时,就会被分配唯一性标识。例如,当使用中文版的浏览器访问 http://www.google.com/ 时,就会返回中文版对应的资源,而使用英文版的浏览器访问时,则会返回英文版对应的资源。两者的 URI 是相同的,所以仅凭 URI 指定缓存的资源是相当困难的。若在下载过程中出现连接中断、再连接的情况,都会依照 ETag 值来指定资源【中文版对应的资源和英文版的ETag不同】。

ETag中有强ETag值和弱ETag值之分:

  • 强ETag值:不论实体发生多么细微的变化都会改变其值。
  • 弱ETag值:只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/。
强:
ETag: "usagi-1234"
弱:
ETag: W/"usagi-1234"

6.5.4 Location

使用首部字段Location 可以将响应接收方引导至某个与请求URI位置不同的资源。

《图解HTTP》——上野 宣_第55张图片

基本上,该字段会配合 3xx :Redirection 的响应,提供重定向的 URI。

几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试对已提示的重定向资源的访问。

6.5.5 Proxy-Authenticate

首部字段 Proxy-Authenticate 会把由代理服务器所要求的认证信息发送给客户端。

6.5.6 Retry-After

首部字段 Retry-After 告知客户端应该在多久之后再次发送请求。主要配合状态码 503 Service Unavailable 响应,或 3xx Redirect 响应一起使用。 字段值可以指定为具体的日期时间(Wed, 04 Jul 2012 06:34:24 GMT 等格式),也可以是创建响应后的秒数。

6.5.7 Server

首部字段 Server 告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不单单会标出服务器上的软件应用名称,还有可能包括版本号和安装时启用的可选项。

《图解HTTP》——上野 宣_第56张图片

Server: Apache/2.2.6 (Unix) PHP/5.2.5

6.5.8 Vary

首部字段 Vary 可对缓存进行控制。源服务器会向代理服务器传达关于本地缓存使用方法的命令。如下图:

《图解HTTP》——上野 宣_第57张图片

如上图,当代理服务器接收到带有 Vary 首部字段指定获取资源的请求时,如果使用的 Accept-Language 字段的值相同,那么就直接从缓存返回响应。反之,则需要先从源服务器端获取资源后才能作为响应返回。

从代理服务器接收到源服务器返回包含 Vary 指定项的响应之后,若再要进行缓存,仅对请求中含有相同 Vary 指定首部字段的请求返回缓存。即使对相同资源发起请求,但由于 Vary 指定的首部字段不相同,因此必须要从源服务器重新获取资源。

6.5.9 WWW-Authenticate

首部字段 WWW-Authenticate 用于 HTTP 访问认证。它会告知客户端适用于访问请求 URI 所指定资源的认证方案(Basic 或是 Digest)和带参数提示的质询(challenge)。状态码 401 Unauthorized 响应中,肯定带有首部字段 WWW-Authenticate。

6.6 实体首部字段

实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部用于补充内容的更新时间等与实体相关的信息

《图解HTTP》——上野 宣_第58张图片

6.6.1 Allow

首部字段 Allow 用于通知客户端能够支持 Request-URI 指定资源的所有 HTTP 方法。当服务器接收到不支持的 HTTP 方法时,会以状态码 405 Method Not Allowed 作为响应返回。与此同时,还会把所有能支持的 HTTP 方法写入首部字段 Allow 后返回。

Allow: GET, HEAD

6.6.2 Content-Encoding

首部字段 Content-Encoding 会告知客户端服务器对实体的主体部分选用的内容编码方式内容编码是指在不丢失实体信息的前提下所进行的压缩

Content-Encoding: gzip

《图解HTTP》——上野 宣_第59张图片

主要采用以下4 种内容编码的方式。

  • gzip
  • compress
  • deflate
  • identity

6.6.3 Content-Language

首部字段 Content-Language 会告知客户端,实体主体使用的自然语言(指中文或英文等语言)。

Content-Language: zh-CN

《图解HTTP》——上野 宣_第60张图片

6.6.4 Content-Length

首部字段 Content-Length 表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用 Content-Length 首部字段。由于实体主体大小的计算方法略微复杂,所以在此不再展开。读者若想一探究竟,可参考 RFC2616 的 4.4。

Content-Length: 15000

《图解HTTP》——上野 宣_第61张图片

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

首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达

Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==

首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整,以及确认传输到达。 对报文主体执行 MD5 算法获得的 128 位二进制数,再通过 Base64 编码后将结果写入 Content-MD5 字段值。由于 HTTP 首部无法记录二进制值,所以要通过 Base64 编码处理。为确保报文的有效性,作为接收方的客户端会对报文主体再执行一次相同的 MD5 算法。计算出的值与字段值作比较后,即可判断出报文主体的准确性。

6.6.7 Content-Range

针对范围请求,返回响应时使用的首部字段 Content-Range,能告知客户端作为响应返回的实体的哪个部分符合范围请求。字段值以字节为单位,表示当前发送部分及整个实体大小。

《图解HTTP》——上野 宣_第62张图片

6.6.8 Content-Type

首部字段 Content-Type 说明了实体主体内对象的媒体类型。和首部字段 Accept 一样,字段值用 type/subtype 形式赋值。

参数 charset 使用 iso-8859-1 或 euc-jp 等字符集进行赋值。

Content-Type: text/html; charset=UTF-8

6.6.9 Expires

首部字段 Expires 会将资源失效的日期告知客户端。缓存服务器在接收到含有首部字段

Expires: Wed, 04 Jul 2012 08:26:05 GMT

《图解HTTP》——上野 宣_第63张图片

会将资源失效的日期告知客户端。缓存服务器在接收到含有首部字段 Expires 的响应后,会以缓存来应答请求,在 Expires 字段值指定的时间之前,响应的副本会一直被保存当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源

源服务器不希望缓存服务器对资源缓存时,最好在 Expires 字段内写入与首部字段 Date 相同的时间值。

但是,当首部字段 Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处理 max-age 指令

6.6.10 Last-Modified

首部字段 Last-Modified 指明资源最终修改的时间。一般来说,这个值就是 Request-URI 指定资源被修改的时间。但类似使用 CGI 脚本进行动态数据处理时,该值有可能会变成数据最终修改时的时间。

6.7 为Cookie服务的首部字段

管理服务器与客户端之间状态的 Cookie,虽然没有被编入标准化 HTTP/1.1 的 RFC2616 中,但在 Web 网站方面得到了广泛的应用。

Cookie 的工作机制是用户识别及状态管理。Web 网站为了管理用户的状态会通过 Web 浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该Web网站时,可通过通信方式取回之前发放的 Cookie。

调用 Cookie 时,由于可校验 Cookie 的有效期,以及发送方的域、路径、协议等信息,所以正规发布的 Cookie 内的数据不会因来自其他 Web 站点和攻击者的攻击而泄露

为Cookie服务的首部字段

首部字段名 说明 首部类型
Set-Cookie 开始状态管理所使用的Cookie信息 响应首部字段
Cookie 服务器接收到的Cookie信息 请求首部字段

6.7.1 Set-Cookie

Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT; path=/; domain=.hackr.jp;

当服务器准备开始管理客户端的状态时,会事先告知各种信息。

下面的表格列举了Set-Cookie的字段值。

属性 说明
NAME=VALUE 赋予Cookie的名称和其值(必需项)
expires=DATE Cookie的有效期(若不明确指定则默认为浏览器关闭前为止)【一旦Cookie从服务器端发送至客户端,服务器端就不存在可以显式删除Cookie的方法,但可以通过覆盖已过期的Cookie,实现对客户端Cookie的实质性删除操作】
path=PATH 将服务器上的文件目录作为Cookies的适用对象(若不指定则默认为文档所在的文件目录)【可用于限制指定Cookie的发送范围的文件目录】
domain=域名 作为Cookie适用对象的域名(若不指定则默认为创建Cookie的服务器的域名)【通过Cookie的domain属性指定的域名可做到与结尾匹配一致,比如,当指定example.com后,除example.com以外,www.example.com或www2.example.com等都可以发送Cookie,因此不指定domin属性更安全】
Secure 仅在HTTPS安全通信时才会发送Cookie【指定Secure属性的方法:Set-Cookie: name=value; secure
HttpOnly 加以限制,使Cookie不能被JavaScript脚本访问【防止跨站脚本攻击(Cross-site scripting,XSS)对Cookie的信息窃取,指定HttpOnly的方式和Secure一样】

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 属于 HTTP 响应首部,用于控制网站内容在其他 Web 网站的 Frame 标签内的显示问题。其主要目的是为了防止点击劫持(clickjacking)攻击。

X-Frame-Options: DENY

首部字段 X-Frame-Options 有以下两个可指定的字段值。

  • DENY: 拒绝

  • SAMEORIGIN:仅同源域名下的页面(Top-level-browsing-context)匹配时许可。(比如,当指定 http://hackr.jp/sample.html 页面为 SAMEORIGIN 时,那么 hackr.jp 上所有页面的 frame 都被允许可加载该页面,而 example.com 等其他域名的页面就不行了)

    上野宣. 图解HTTP (Kindle 位置 1709-1711). Kindle 版本.

对 apache2.conf 的配置实例

<IfModule mod_headers.c>    
	Header append X-FRAME-OPTIONS "SAMEORIGIN"
</IfModule>

6.8.2 X-XSS-Protection

首部字段 X-XSS-Protection 属于 HTTP 响应首部,它是针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器 XSS 防护机制的开关

X-XSS-Protection: 1

首部字段X-XSS-Protection可指定的字段值如下:

  • 0:将XSS过滤设置成无状态
  • 1:将XSS过滤设置成有效状态

6.8.3 DNT

首部字段 DNT 属于 HTTP 请求首部,其中 DNT 是 Do Not Track 的简称,意为拒绝个人信息被收集,是表示拒绝被精准广告追踪的一种方法。

DNT: 1

首部字段 DNT 可指定的字段值如下。

  • 0:同意被追踪
  • 1:拒绝被追踪

由于首部字段DNT的功能具备有效性,所以Web服务器需要对DNT做对应的支持。

6.8.4 P3P

首部字段 P3P 属于 HTTP 响应首部通过利用 P3P(The Platform for Privacy Preferences,在线隐私偏好平台)技术,可以让 Web 网站上的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的目的

P3P: CP="CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT"

要进行P3P的设定,需按以下操作步骤进行。

步骤1:创建P3P隐私。

步骤 2 :创建 P3P 隐私对照文件后,保存命名在 /w3c/p3p.xml

步骤 3 :从 P3P 隐私中新建 Compact policies 后,输出到 HTTP 响应中

协议中对X-前缀的废除

在 HTTP 等多种协议中,通过给非标准参数加上前缀 X-,来区别于标准参数,并使那些非标准的参数作为扩展变成可能。但是这种简单粗暴的做法有百害而无一益,因此在“RFC 6648 - Deprecating the “X-” Prefix and Similar Constructs in Application Protocols”中提议停止该做法。 然而,对已经在使用中的 X- 前缀来说,不应该要求其变更。

第七章、确保Web安全的HTTPS

7.1 HTTP的缺点

HTTP主要有这些包不足:

  • 通信使用明文(不加密),内容可能会被窃听
  • 不验证通信方的身份,因此有可能遭遇伪装
  • 无法证明报文的完整性,所以有可能已遭篡改

这些问题不仅在 HTTP 上出现,其他未加密的协议中也会存在这类问题。

除此之外,HTTP 本身还有很多缺点。而且,还有像某些特定的 Web 服务器和特定的 Web 浏览器在实际应用中存在的不足(也可以说成是脆弱性或安全漏洞),另外,用 Java 和 PHP 等编程语言开发的 Web 应用也可能存在安全漏洞。

7.1.1 通信使用明文可能会被窃听

由于 HTTP 本身不具备加密的功能,所以也无法做到对通信整体(使用 HTTP 协议通信的请求和响应的内容)进行加密。即,HTTP 报文使用明文(指未经过加密的报文)方式发送。

TCP/IP 是可能会被窃听的网络

如果要问为什么通信时不加密是一个缺点,这是因为,按 TCP/IP 协议族的工作机制,通信内容在所有的通信线路上都有可能遭到窥视

即使已经过加密处理的通信,也会被窥视到通信内容,这点和未加密的通信是相同的。只是说如果通信经过加密,就有可能让人无法破解报文信息的含义,但加密处理后的报文信息本身还是会被看到的。

《图解HTTP》——上野 宣_第64张图片

加密处理防止被窃听

加密的处理的对象可以由这么几个:

  • 通信的加密:HTTP 协议中没有加密机制,但可以通过和 SSL(Secure Socket Layer,安全套接层)或 TLS(Transport Layer Security,安全层传输协议)的组合使用,加密 HTTP 的通信内容。与 SSL 组合使用的 HTTP 被称为 **HTTPS(HTTP Secure,超文本传输安全协议)**或 HTTP over SSL。
  • 内容的加密:由于 HTTP 协议中没有加密机制,那么就对 HTTP 协议传输的内容本身加密。即把 HTTP 报文里所含的内容进行加密处理。

内容加密的情况下,客户端需要对HTTP报文进行加密处理后再发送出来:

《图解HTTP》——上野 宣_第65张图片

诚然,为了做到有效的内容加密,前提是要求客户端和服务器同时具备加密和解密机制。主要应用在 Web 服务中。有一点必须引起注意,由于该方式不同于 SSL 或 TLS 将整个通信线路加密处理,所以内容仍有被篡改的风险

7.1.2 不验证通信方的身份就可能遭遇伪装

HTTP 协议中的请求和响应不会对通信方进行确认。也就是说存在“服务器是否就是发送请求中 URI 真正指定的主机,返回的响应是否真的返回到实际提出请求的客户端”等类似问题。

《图解HTTP》——上野 宣_第66张图片

HTTP 协议的实现本身非常简单,不论是谁发送过来的请求都会返回响应,因此不确认通信方,会存在以下各种隐患。

  • 无法确定发送至目标的Web服务器是不是已伪装的Web服务器
  • 无法确定响应返回到的客户端是不是已伪装的客户端
  • 无法确定正在通信的对方是否具备访问权限
  • 无法判定请求是来自何方、出自谁手
  • 即使是无意义的请求也会照单全收。无法阻止海量请求下的Dos攻击(Denial of Service,拒绝服务攻击)

SSL证书验证通讯方身份

虽然使用 HTTP 协议无法确定通信方,但如果使用 SSL 则可以。SSL 不仅提供加密处理,而且还使用了一种被称为证书的手段,可用于确定方。 证书由值得信任的第三方机构颁发,用以证明服务器和客户端是实际存在的。另外,伪造证书从技术角度来说是异常困难的一件事。所以只要能够确认通信方(服务器或客户端)持有的证书,即可判断通信方的真实意图。

7.1.3 无法证明报文完整性,可能已被篡改

由于 HTTP 协议无法证明通信的报文完整性,因此,在请求或响应送出之后直到对方接收之前的这段时间内,即使请求或响应的内容遭到篡改,也没有办法获悉。 换句话说,没有任何办法确认,发出的请求 / 响应和接收到的请求 / 响应是前后相同的。

像这样,请求或响应在传输途中,遭攻击者拦截并篡改内容的攻击称为中间人攻击(Man-in-the-Middle attack,MITM)。

《图解HTTP》——上野 宣_第67张图片

SSL提供认证和加密处理及摘要功能防止报文被修改

虽然有使用 HTTP 协议确定报文完整性的方法,但事实上并不便捷、可靠。其中常用的是 MD5 和 SHA-1 等散列值校验的方法,以及用来确认文件的数字签名方法。

提供文件下载服务的 Web 网站也会提供相应的以 PGP(Pretty Good Privacy,完美隐私)创建的数字签名及 MD5 算法生成的散列值。PGP 是用来证明创建文件的数字签名,MD5 是由单向函数生成的散列值。

不论使用哪一种方法,都需要操纵客户端的用户本人亲自检查验证下载的文件是否就是原来服务器上的文件。浏览器无法自动帮用户检查。 可惜的是,用这些方法也依然无法百分百保证确认结果正确。因为 PGP 和 MD5 本身被改写的话,用户是没有办法意识到的

为了有效防止这些弊端,有必要使用 HTTPS。SSL 提供认证和加密处理及摘要功能。仅靠 HTTP 确保完整性是非常困难的,因此通过和其他协议组合使用来实现这个目标。

7.2 HTTP + 加密 + 认证 + 完整性保护 = HTTPS

7.2.1 HTTP加上加密处理和认证以及完整性保护后即是HTTPS

使用HTTPS通信:

《图解HTTP》——上野 宣_第68张图片

经常会在 Web 的登录页面和购物结算界面等使用 HTTPS 通信。使用 HTTPS 通信时,不再用 http://,而是改用 https://。另外,当浏览器访问 HTTPS 通信有效的 Web 网站时,浏览器的地址栏内会出现一个带锁的标记。对 HTTPS 的显示方式会因浏览器的不同而有所改变。

《图解HTTP》——上野 宣_第69张图片

7.2.2 HTTPS是身披SSL外壳的HTTP

HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用 SSL(Secure Socket Layer)和 TLS(Transport Layer Security)协议代替而已。 通常,HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL 和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的 HTTP。

《图解HTTP》——上野 宣_第70张图片

在采用 SSL 后,HTTP 就拥有了 HTTPS 的加密、证书和完整性保护这些功能。

SSL 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应用层的 SMTP 和 Telnet 等协议均可配合 SSL 协议使用。可以说 SSL 是当今世界上应用最为广泛的网络安全技术

7.2.3 相互交换密钥的公开密钥加密技术

在对 SSL 进行讲解之前,我们先来了解一下加密方法。SSL 采用一种叫做公开密钥加密(Public-key cryptography)的加密处理方式。

近代的加密方法中加密算法是公开的,而密钥却是保密的。通过这种方式得以保持加密方法的安全性。

共享密钥加密的困境

加密和解密同用一个密钥的方式称为共享密钥加密(Common key crypto system),也被叫做对称密钥加密。

《图解HTTP》——上野 宣_第71张图片

加密和解密都会用到密钥。没有密钥就无法对密码解密,反过来说,任何人只要持有密钥就能解密了。如果密钥被攻击者获得,那加密也就失去了意义。

使用两把密钥的公开密钥加密

公开密钥加密方式很好地解决了共享密钥加密的困难

公开密钥加密使用一对非对称的密钥。一把叫做私有密钥(private key),另一把叫做公开密钥(public key)。顾名思义,私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。 使用公开密钥加密方式,发送密文的一方使用对方的公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。

利用这种方式,不需要发送用来解密的私有密钥,也不必担心密钥被攻击者窃听而盗走。 另外,要想根据密文和公开密钥,恢复到信息原文是异常困难的,因为解密过程就是在对离散对数进行求值,这并非轻而易举就能办到。退一步讲,如果能对一个非常大的整数做到快速地因式分解,那么密码破解还是存在希望的。但就目前的技术来看是不太现实的。

HTTPS采用混合加密机制

HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制。若密钥能够实现安全交换,那么有可能会考虑仅使用公开密钥加密来通信。但是公开密钥加密与共享密钥加密相比,其处理速度要慢。

所以应充分利用两者各自的优势,将多种方法组合起来用于通信。在交换密钥环节使用公开密钥加密方式,之后的建立通信交换报文阶段则使用共享密钥加密方式

在这里插入图片描述

7.2.4 证明公开密钥正确性的证书

遗憾的是,公开密钥加密方式还是存在一些问题的。那就是无法证明公开密钥本身就是货真价实的公开密钥。比如,正准备和某台服务器建立公开密钥加密方式下的通信时,如何证明收到的公开密钥就是原本预想的那台服务器发行的公开密钥。或许在公开密钥传输途中,真正的公开密钥已经被攻击者替换掉了。

为了解决上述问题,可以使用由数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书。

7.2.5 HTTPS 的安全通信机制

SSL速度慢吗

HTTPS 也存在一些问题,那就是当使用 SSL 时,它的处理速度会变慢。

HTTPS比HTTP要慢2到100倍

《图解HTTP》——上野 宣_第72张图片

SSL 的慢分两种。

一种是指通信慢。另一种是指由于大量消耗 CPU 及内存等资源,导致处理速度变慢

和使用 HTTP 相比,网络负载可能会变慢 2 到 100 倍。

除去和 TCP 连接、发送 HTTP 请求 • 响应以外,还必须进行 SSL 通信,因此整体上处理通信量不可避免会增加。

另一点是 SSL 必须进行加密处理。在服务器和客户端都需要进行加密和解密的运算处理。

因此从结果上讲,比起 HTTP 会更多地消耗服务器和客户端的硬件资源,导致负载增强。

针对速度变慢这一问题,并没有根本性的解决方案,我们会使用 SSL 加速器这种(专用服务器)硬件来改善该问题。该硬件为 SSL 通信专用硬件,相对软件来讲,能够提高数倍 SSL 的计算速度。仅在 SSL 处理时发挥 SSL 加速器的功效,以分担负载。

为什么不一直使用HTTPS

其中一个原因是,因为与纯文本通信相比,加密通信会消耗更多的 CPU 及内存资源。如果每次通信都加密,会消耗相当多的资源,平摊到一台计算机上时,能够处理的请求数量必定也会随之减少。

因此,如果是非敏感信息则使用 HTTP 通信,只有在包含个人信息等敏感数据时,才利用 HTTPS 加密通信。

特别是每当那些访问量较多的 Web 网站在进行加密处理时,它们所承担着的负载不容小觑。在进行加密处理时,并非对所有内容都进行加密处理,而是仅在那些需要信息隐藏时才会加密,以节约资源。

除此之外,想要节约购买证书的开销也是原因之一。 要进行 HTTPS 通信,证书是必不可少的。而使用的证书必须向认证机构(CA)购买。证书价格可能会根据不同的认证机构略有不同。通常,一年的授权需要大约 600 人民币。 那些购买证书并不合算的服务以及一些个人网站,可能只会选择采用 HTTP 的通信方式。

第八章、确认访问用户身份的认证

8.1 何为认证

计算机本身无法判断坐在显示器前的使用者的身份。进一步说,也无法确认网络的那头究竟有谁。可见,为了弄清究竟是谁在访问服务器,就得让对方的客户端自报家门。

核对的信息通常是指以下这些:

  • 密码:只有本人才会知道的字符串信息。
  • 动态令牌:仅限本人持有的设备内显示的一次性密码。
  • 数字证书:仅限本人(终端)持有的信息。
  • 生物认证:指纹和虹膜等本人的生理信息。
  • IC卡等:仅限本人持有的信息。

HTTP使用的认证方式

HTTP/1.1 使用的认证方式如下所示:

  • BASIC认证(基本认证)
  • DIGEST认证(摘要认证)
  • SSL客户端认证
  • FormBase认证(基于表单认证)

此外,还有Windows统一认证(Keberos认证、NTLM认证),但此书不作讲解。

8.2 BASIC认证

BASIC 认证(基本认证)是从 HTTP/1.0 就定义的认证方式。即便是现在仍有一部分的网站会使用这种认证方式。是 Web 服务器与通信客户端之间进行的认证方式。

BASIC认证概要:

《图解HTTP》——上野 宣_第73张图片

步骤 1 : 当请求的资源需要 BASIC 认证时,服务器会随状态码 401 Authorization Required,返回带 WWW-Authenticate 首部字段的响应。该字段内包含认证的方式(BASIC) 及 Request-URI 安全域字符串(realm)。

步骤 2 : 接收到状态码 401 的客户端为了通过 BASIC 认证,需要将用户 ID 及密码发送给服务器。发送的字符串内容是由用户 ID 和密码构成,两者中间以冒号(:)连接后,再经过 Base64 编码处理。 假设用户 ID 为 guest,密码是 guest,连接起来就会形成 guest:guest 这样的字符串。然后经过 Base64 编码,最后的结果即是 Z3Vlc3Q6Z3Vlc3Q=。把这串字符串写入首部字段 Authorization 后,发送请求。

步骤 3 : 接收到包含首部字段 Authorization 请求的服务器,会对认证信息的正确性进行验证。如验证通过,则返回一条包含 Request-URI 资源的响应。 BASIC 认证虽然采用 Base64 编码方式,但这不是加密处理。不需要任何附加信息即可对其解码。换言之,由于明文解码后就是用户 ID 和密码,在 HTTP 等非加密通信的线路上进行 BASIC 认证的过程中,如果被人窃听,被盗的可能性极高。

另外,除此之外想再进行一次 BASIC 认证时,一般的浏览器却无法实现认证注销操作,这也是问题之一

BASIC 认证使用上不够便捷灵活,且达不到多数 Web 网站期望的安全性等级,因此它并不常用。

8.3 DIGEST认证

为弥补 BASIC 认证存在的弱点,从 HTTP/1.1 起就有了 DIGEST 认证。 DIGEST 认证同样使用质询 / 响应的方式(challenge/response),但不会像 BASIC 认证那样直接发送明文密码

所谓质询响应方式是指,一开始一方会先发送认证要求给另一方,接着使用从另一方那接收到的质询码计算生成响应码。最后将响应码返回给对方进行认证的方式

《图解HTTP》——上野 宣_第74张图片

因为发送给对方的只是响应摘要及由质询码产生的计算结果,所以比起 BASIC 认证,密码泄露的可能性就降低了

《图解HTTP》——上野 宣_第75张图片

DIGEST 认证提供了高于 BASIC 认证的安全等级,但是和 HTTPS 的客户端认证相比仍旧很弱。

DIGEST 认证提供防止密码被窃听的保护机制,但并不存在防止用户伪装的保护机制

DIGEST 认证和 BASIC 认证一样,使用上不那么便捷灵活,且仍达不到多数 Web 网站对高度安全等级的追求标准。因此它的适用范围也有所受限。

8.4 SSL客户端认证

从使用用户 ID 和密码的认证方式方面来讲,只要二者的内容正确,即可认证是本人的行为。

但如果用户 ID 和密码被盗,就很有可能被第三者冒充。利用 SSL 客户端认证则可以避免该情况的发生

SSL 客户端认证是借由 HTTPS 的客户端证书完成认证的方式。凭借客户端证书(在 HTTPS 一章已讲解)认证,服务器可确认访问是否来自已登录的客户端。

8.4.1 SSL客户端认证的认证步骤

为达到 SSL 客户端认证的目的,需要事先将客户端证书分发给客户端,且客户端必须安装此证书。

步骤 1 : 接收到需要认证资源的请求,服务器会发送 Certificate Request 报文,要求客户端提供客户端证书。

步骤 2 : 用户选择将发送的客户端证书后,客户端会把客户端证书信息以 Client Certificate 报文方式发送给服务器。

步骤 3 : 服务器验证客户端证书验证通过后方可领取证书内客户端的公开密钥,然后开始 HTTPS 加密通信。

8.4.2 SSL客户端认证采用双因素认证

在多数情况下,SSL 客户端认证不会仅依靠证书完成认证,一般会和基于表单认证(稍后讲解)组合形成一种双因素认证(Two-factor authentication)来使用。所谓双因素认证就是指,认证过程中不仅需要密码这一个因素,还需要申请认证者提供其他持有信息,从而作为另一个因素,与其组合使用的认证方式

换言之,第一个认证因素的 SSL 客户端证书用来认证客户端计算机,另一个认证因素的密码则用来确定这是用户本人的行为。

通过双因素认证后,就可以确认是用户本人正在使用匹配正确的计算机访问服务器。

8.5 基于表单认证

基于表单的认证方法并不是在 HTTP 协议中定义的。客户端会向服务器上的 Web 应用程序发送登录信息(Credential),按登录信息的验证结果认证。

8.5.1 认证多半为基于表单认证

由于使用上的便利性及安全性问题,HTTP 协议标准提供的 BASIC 认证和 DIGEST 认证几乎不怎么使用。另外,SSL 客户端认证虽然具有高度的安全等级,但因为导入及维持费用等问题,还尚未普及。

比如 SSH 和 FTP 协议,服务器与客户端之间的认证是合乎标准规范的,并且满足了最基本的功能需求上的安全使用级别,因此这些协议的认证可以拿来直接使用。但是对于 Web 网站的认证功能,能够满足其安全使用级别的标准规范并不存在,所以只好使用由 Web 应用程序各自实现基于表单的认证方式。 不具备共同标准规范的表单认证,在每个 Web 网站上都会有各不相同的实现方式。如果是全面考虑过安全性能而实现的表单认证,那么就能够具备高度的安全等级。但在表单认证的实现中存在问题的 Web 网站也是屡见不鲜。

8.5.2 Session管理及Cookie应用

基于表单认证的标准规范尚未有定论,一般会使用 Cookie 来管理 Session(会话)。

基于表单认证本身是通过服务器端的 Web 应用,将客户端发送过来的用户 ID 和密码与之前登录过的信息做匹配来进行认证的。

鉴于 HTTP 是无状态协议,之前已认证成功的用户状态无法通过协议层面保存下来。即,无法实现状态管理,因此即使当该用户下一次继续访问,也无法区分他与其他的用户。于是我们会使用 Cookie 来管理 Session,以弥补 HTTP 协议中不存在的状态管理功能。

Session管理及Cookie状态管理:

《图解HTTP》——上野 宣_第76张图片

另外,不仅基于表单认证的登录信息及认证过程都无标准化的方法,服务器端应如何保存用户提交的密码等登录信息等也没有标准化。

通常,一种安全的保存方法是,先利用**给密码加盐(salt)**的方式增加额外信息,再使用散列(hash)函数计算出散列值后保存。但是我们也经常看到直接保存明文密码的做法,而这样的做法具有导致密码泄露的风险。

salt 其实就是由服务器随机生成的一个字符串,但是要保证长度足够长,并且是真正随机生成的。然后把它和密码字符串相连接(前后都可以)生成散列值。当两个用户使用了同一个密码时,由于随机生成的 salt 值不同,对应的散列值也将是不同的。这样一来,很大程度上减少了密码特征,攻击者也就很难利用自己手中的密码特征库进行破解。

第九章、基于HTTP的功能追加协议

9.1 消除HTTP瓶颈的SPDY

在 Facebook 和 Twitter 等 SNS 网站上,几乎能够实时观察到海量用户公开发布的内容,这也是一种乐趣。当几百、几千万的用户发布内容时,Web 网站为了保存这些新增内容,在很短的时间内就会发生大量的内容更新。

为了尽可能实时地显示这些更新的内容,服务器上一有内容更新,就需要直接把那些内容反馈到客户端的界面上。虽然看起来挺简单的,但 HTTP 却无法妥善地处理好这项任务

使用 HTTP 协议探知服务器上是否有内容更新,就必须频繁地从客户端到服务器端进行确认。如果服务器上没有内容更新,那么就会产生徒劳的通信。 若想在现有 Web 实现所需的功能,以下这些 HTTP 标准就会成为瓶颈。

  • 一条连接上只可发送一个请求。
  • 请求只能从客户端开始。客户端不可以接收除响应以外的指令。
  • 请求 / 响应首部未经压缩就发送。首部信息越多延迟越大。
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多。
  • 可任意选择数据压缩格式。非强制压缩发送。

Ajax的解决方法

Ajax(Asynchronous JavaScript and XML, 异 步 JavaScript 与 XML 技术)是一种有效利用 JavaScript 和 DOM(Document Object Model,文档对象模型)的操作,以达到局部 Web 页面替换加载的异步通信手段。和以前的同步通信相比,由于它只更新一部分页面,响应中传输的数据量会因此而减少,这一优点显而易见。

Ajax 的核心技术是名为 XMLHttpRequest 的 API,通过 JavaScript 脚本语言的调用就能和服务器进行 HTTP 通信。借由这种手段,就能从已加载完毕的 Web 页面上发起请求,只更新局部页面。

而利用 Ajax 实时地从服务器获取内容,有可能会导致大量请求产生。另外,Ajax 仍未解决 HTTP 协议本身存在的问题。

Comet的解决方法

一旦服务器端有内容更新了,Comet 不会让请求等待,而是直接给客户端返回响应。这是一种通过延迟应答,模拟实现服务器端向客户端推送(Server Push)的功能。

通常,服务器端接收到请求,在处理完毕后就会立即返回响应,但为了实现推送功能,Comet 会先将响应置于挂起状态,当服务器端有内容更新时,再返回该响应。因此,服务器端一旦有更新,就可以立即反馈给客户端。

内容上虽然可以做到实时更新,但为了保留响应,一次连接的持续时间也变长了。期间,为了维持连接会消耗更多的资源。另外,Comet 也仍未解决 HTTP 协议本身存在的问题。

SPDY的目标

陆续出现的 Ajax 和 Comet 等提高易用性的技术,一定程度上使 HTTP 得到了改善,但 HTTP 协议本身的限制也令人有些束手无策。为了进行根本性的改善,需要有一些协议层面上的改动。 处于持续开发状态中的 SPDY 协议,正是为了在协议级别消除 HTTP 所遭遇的瓶颈。

9.1.1 SPDY的设计与功能

**SPDY 没有完全改写 HTTP 协议,而是在 TCP/IP 的应用层与运输层之间通过新加会话层的形式运作。**同时,考虑到安全性问题,SPDY 规定通信中使用 SSL。 SPDY 以会话层的形式加入,控制对数据的流动,但还是采用 HTTP 建立通信连接。因此,可照常使用 HTTP 的 GET 和 POST 等方 法、Cookie 以及 HTTP 报文等。

《图解HTTP》——上野 宣_第77张图片

使用SPDY后,HTTP协议额外获得以下功能:

  1. 多路复用流:通过单一的TCP连接,可以无限处理多个HTTP请求。所有请求的处理都在一条TCP连接上完成,因此TCP的处理效率得到提高。
  2. 赋予请求优先级:SPDY不仅可以无限制地并发处理请求,还可以给请求逐个分配优先级顺序。这样主要是为了在发送多个请求时,解决因带宽低导致响应变慢的问题。
  3. 压缩HTTP的首部:压缩HTTP的请求和响应的首部。这样一来,通信产生的数据包数量和发送的字节数就更少了。
  4. 推送功能:支持服务器主动向客户端推送数据的功能。这样,服务器可直接发送数据,而不必等待客户端的请求。
  5. 服务器提示功能:服务器可以主动提示客户端请求所需的资源。由于在客户端发现资源之前就可以获知资源的存在,因此在资源已缓存等情况下,可以避免发送不必要的请求。

9.2 使用浏览器进行全双工通信的WebSocket

利用 Ajax 和 Comet 技术进行通信可以提升 Web 的浏览速度。但问题在于通信若使用 HTTP 协议,就无法彻底解决瓶颈问题。WebSocket 网络技术正是为解决这些问题而实现的一套新协议及 API。

一旦 Web 服务器与客户端之间建立起 WebSocket 协议的通信连接,之后所有的通信都依靠这个专用协议进行。通信过程中可互相发送 JSON、XML、HTML 或图片等任意格式的数据。

由于是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。

下面我们列举一下 WebSocket 协议的主要特点。

  1. 推送功能:支持由服务器向客户端推送数据的推送功能。这样,服务器可直接发送数据,而不必等待客户端的请求。

  2. 减少通信量 只要建立起 WebSocket 连接,就希望一直保持连接状态。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了。 为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次“握手”(Handshaking)的步骤。

《图解HTTP》——上野 宣_第78张图片

9.3 期盼已久的HTTP/2.0

HTTP/2.0 的目标是改善用户在使用 Web 时的速度体验。由于基本上都会先通过 HTTP/1.1 与 TCP 连接,现在我们以下面的这些协议为基础,探讨一下它们的实现方法。

  • SPDY
  • HTTP Speed + Mobility
  • Network-Friendly HTTP Upgrade

HTTP Speed + Mobility 由微软公司起草,是用于改善并提高移动端通信时的通信速度和性能的标准。它建立在Google公司提出的SPDY与WebSocket的基础之上。

Network-Friendly HTTP Upgrade 主要是在移动端通信时改善HTTP性能的标准。

HTTP/2.0的7项技术及讨论

技术名 技术基础
压缩 SPDY、Friendly
多路复用 SPDY
TLS义务化 Speed+Mobility
协商 Speed+Mobility,Friendly
客户端拉曳(Client Pull)/ 服务器推送(Server Push) Speed + Mobility
流量控制 SPDY
WebSocket Speed + Mobility

注:HTTP Speed + Mobility 简写为 Speed + Mobility,Network-Friendly HTTP Upgrade 简写为 Friendly。

9.4 Web服务器管理文件的WebDAV

WebDAV(Web-based Distributed Authoring and Versioning,基于万维网的分布式创作和版本控制)是一个可对 Web 服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统。它作为扩展 HTTP/1.1 的协议定义在 RFC4918。

除了创建、删除文件等基本功能,它还具备文件创建者管理、文件编辑过程中禁止其他用户内容覆盖的加锁功能,以及对文件内容修改的版本控制功能。

《图解HTTP》——上野 宣_第79张图片

使用 HTTP/1.1 的 PUT 方法和 DELETE 方法,就可以对 Web 服务器上的文件进行创建和删除操作。可是出于安全性及便捷性等考虑,一般不使用。

第十章、构建Web内容的技术

10.1 可扩展标记语言

XML(eXtensible Markup Language,可扩展标记语言)是一种可按应用目标进行扩展的通用标记语言。旨在通过使用 XML,使互联网数据共享变得更容易。

XML 和 HTML 都是从标准通用标记语言 SGML(Standard Generalized Markup Language)简化而成。与 HTML 相比,它对数据的记录方式做了特殊处理。 下面我们以 HTML 编写的某公司的研讨会议议程为例进行说明。

 <html>
     <head>
     	<title>T公司研讨会介绍</title>
	</head>
	<body>
     	<h1>T公司研讨会介绍</h1>
		<ul>
     		<li>研讨会编号:TR001
				<ul>       
     				<li>Web应用程序脆弱性诊断讲座</li>
				</ul>
		   <li>研讨会编号:TR002
				<ul>
     				<li>网络系统脆弱性诊断讲座</li>
				</ul>
		   </li>
		</ul>
	</body>
</html>

用浏览器打开该文档时,就会显示排列的列表内容,但如果这些数据被其他程序读取会发生什么?某些程序虽然具备可通过识别布局特征取出文本的方法,但这份 HTML 的样式一旦改变,要读取数据内容也就变得相对困难了。可见,为了保持数据的正确读取,HTML 不适合用来记录数据结构。 接着将这份列表以 XML 的形式改写就成了以下的示例。

<研讨会 编号="TR001" 主题="Web应用程序脆弱性诊断讲座">
    < 类别 > 安全 类别>   
    < 概要 >为深入研究Web应用程序脆弱性诊断必要的…概要> 
研讨会>
<研讨会 编号="TR002" 主题="网络系统脆弱性诊断讲座">
    < 类别 > 安全 类别>
    < 概要 >为深入研究网络系统脆弱性诊断必要的…概要>
研讨会>

XML 和 HTML 一样,使用标签构成树形结构,并且可自定义扩展标签。

从 XML 文档中读取数据比起 HTML 更为简单。由于 XML 的结构基本上都是用标签分割而成的树形结构,因此通过语法分析器(Parser)的解析功能解析 XML 结构并取出数据元素,可更容易地对数据进行读取。

更容易地复用数据使得 XML 在互联网上被广泛接受。比如,可用在 2 个不同的应用之间的交换数据格式化。

10.2 JavaScript衍生的轻量级易用JSON

JSON(JavaScript Object Notation)是一种以 JavaScript(ECMAScript)的对象表示法为基础的轻量级数据标记语言。能够处理的数据类型有 false/null/true/ 对象 / 数组 / 数字 / 字符串,这 7 种类型。

{"name": "Web Application Security", "num": "TR001"} 

JSON 让数据更轻更纯粹,并且 JSON 的字符串形式可被 JavaScript 轻易地读入。当初配合 XML 使用的 Ajax 技术也让 JSON 的应用变得更为广泛。另外,其他各种编程语言也提供丰富的库类,以达到轻便操作 JSON 的目的。

你可能感兴趣的:(网络&请求,知识积累,http,网络协议,网络,笔记,前端)