HTTP 协议

引言

最近在读上野宣的《图解HTTP》。虽然已经做了大大小小的好些个Web项目了,现在再回过头来看HTTP协议,听起来似乎有点本末倒置,但我觉得如果先实践,有了对实践成果的先入为主的、直观的认识以后,再去探究理论与原理就会容易得多。

上野宣的这本书确实值得一读,相比另外一本鼻祖书籍《HTTP权威指南》而言,加入了更多生动鲜活的插图和注解,使得HTTP这个较为抽象死板的协议很容易被人理解。全书不仅易读,知识体系还非常完整,不仅讲解了老的理论知识与技术,还拓展了HTTPS、WebSocket、Web构建技术、Web安全、Web攻击等一些非常实用的内容。

本文不对HTTP协议进行巨细无遗地阐述,而是从我个人对HTTP协议的掌握情况出发,梳理一些容易被忽略和遗忘的知识点。

简单的HTTP协议

1 请求报文结构

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

http1

2 响应报文结构

响应报文基本上由协议版本、状态码(表示请求成功或失败的数字代码)、用以解释状态码的原因短语、可选的响应首部字段以及实体主体构成。

http2

3 HTTP的无状态性

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

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

可是,随着 Web 的不断发展,因无状态而导致业务处理变得棘手的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的 其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,需要保存用户的状态。

HTTP/1.1 虽然是无状态协议,但为了实现期望的保持状态功能, 于是引入了 Cookie 技术。有了 Cookie 再用 HTTP 协议通信,就可以管 理状态了。

4 HTTP方法

  • GET:获取资源
  • POST:传输实体主体
  • PUT:传输文件
  • DELETE:删除文件
  • HEAD:获得报文首部
  • OPTION:询问支持的方法(跨域访问)
  • TRACE:追踪路径
  • CONNECT:要求用隧道协议连接代理

5 状态码类别

数字中的第一位指定了响应类别,后两位无分类。响应类别有以下5种。

http3

HTTP协作服务器

1 代理

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

http4

代理主要分为两种:

  • 缓存代理:代理转发响应时,缓存代理(Caching Proxy)会预先将资源的副本 (缓存)保存在代理服务器上。当代理再次接收到对相同资源的请求时,就可以不从源服务器那里 获取资源,而是将之前缓存的资源作为响应返回。
  • 透明代理:转发请求或响应时,不对报文做任何加工的代理类型被称为透明代 理(Transparent Proxy)。反之,对报文内容进行加工的代理被称为 非透明代理。

2 网关

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

http5

3 隧

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

http6

HTTPS

HTTP协议简单方便,但也有不足之处:

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

采用HTTPS可以有效解决上面问题。HTTPS 并非是应用层的一种新协议,只是 HTTP 通信接口部分用 SSL(Secure Socket Layer)和 TLS(Transport Layer Security)协议代替而已,这样可以实现加密、认证与完整性保护。

HTTPS 采用共享密钥加密(加解密是一个密钥)和公开密钥加密(加密用公钥,解密用私钥)两者并用的混合加密机 制。若密钥能够实现安全交换,那么有可能会考虑仅使用公开密钥加密来通信。但是公开密钥加密与共享密钥加密相比,其处理速度要慢。所以HTTPS充分利用了两者各自的优势,将多种方法组合起来用于通信。 在交换密钥环节使用公开密钥加密方式,之后的建立通信交换报文阶段 则使用共享密钥加密方式。

http7

但由于HTTPS要做服务器、客户端双方加密和解密处理,会消耗CPU与内存等硬件资源,和使用HTTP相比,网络负载会拖慢速度2-100倍,目前尚无根本性的解决方案,一般而言是采用 SSL 加速器这种(专用服务器)硬件来改善该问题。该硬件为 SSL 通信专用硬件,相对软件来讲,能够提高数倍 SSL 的计算速度。仅在 SSL 处理时发挥 SSL 加速器的功效,以分担负载。

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

数字证书认证

公开密钥加密方式还是存在一些问题的。那就是无法证 明公开密钥本身就是货真价实的公开密钥。比如,正准备和某台服务器建立公开密钥加密方式下的通信时,如何证明收到的公开密钥就是原本 预想的那台服务器发行的公开密钥。或许在公开密钥传输途中,真正的公开密钥已经被攻击者替换掉了。为了解决上述问题,可以使用由数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书。其过程如下图所示:

http8

HTTP功能追加协议

在建立HTTP标准规范时,初衷是希望用其来传递HTML文档。但随时代发展,Web应用的用途越发多样化,HTTP 协议上的限制以及自身性能的缺陷也越发明显。

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

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

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

1 Ajax

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

http9

2 Comet

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

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

http10

3 WebSocket

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

一旦 Web 服务器与客户端之间建立起 WebSocket 协议的通信连接, 之后所有的通信都依靠这个专用协议进行。通信过程中可互相发送 JSON、XML、HTML 或图片等任意格式的数据。由于是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。下面是WebSocket协议的主要特点:

1) 推送功能

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

2) 减少通信量

只要建立起 WebSocket 连接,就希望一直保持连接状态。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部 信息很小,通信量也相应减少了。

采用WebSocket协议通信的过程如下图所示:

http11

调用WebSocket API,每50ms发送一次数据的代码如下:

var socket = new WebSocket('ws://game.example.com:12010/updates'); 
socket.onopen = function () {
    setInterval(function() {
      if (socket.bufferedAmount == 0)
        socket.send(getUpdateData());
    }, 50);
};

Web应用

原本应用 HTTP 协议的 Web 的机制就是对客户端发来的请求,返回事前准备好的内容。可随着 Web 越来越普及,仅靠这样的做法已不 足以应对所有的需求,更需要引入由程序创建 HTML 内容的做法。

Servlet

Servlet是一种能在服务器上创建动态内容的程序。Servlet 是用 Java 语言实现的一个接口,属于面向企业级 Java(JavaEE,Java Enterprise Edition)的一部分。Servlet运行在与 Web 服务器相同的进程中,因此受到的负载较小 。Servlet 的运行环境叫做 Web 容器或 Servlet 容器。

http12

数据发布格式

在Web应用的前后端交换数据时需要采用统一的格式,其实从HTTP协议的设计初衷出发,数据交换的单位应该是HTML文档,但随着Ajax异步通信的掀起,我们往往不需要更新整个页面,而是拿到数据后,对页面中的局部部分进行更新,而采用最多的通信格式即是XML与JSON,其中JSON基本已成为主流。

1 XML

XML和HTML一样,使用标签构成树形结构,并且可自定义扩展标签。从XML 文档中读取数据比起 HTML 更为简单。由于 XML 的结构基本上都是用标签分割而成的树形结构(仅能有一个根节点,但可以嵌套),因此通过语法分析器(Parser) 的解析功能解析 XML 结构并取出数据元素,可更容易地对数据进行读取。

XML的解析方式分为SAX与DOM两种:

  • SAX解析:基于事件驱动,按行读取,每遇到一个开始/结束标签、属性、指令时,程序就产生一个事件来进行相应的处理。所以在操作文档之前不需要对整个文档进行解析。实际上,文档的各个部分可以在进行解 析的同时进行操作,过程上比较像读取流。
  • DOM解析:基于DOM树,一般按照DSF(Depth Search First)在内存中构建整个XML文档对应的DOM树,不仅可以在某个节点进行上下切换,还可对节点内容进行修改。

下表是这两种解析方式的区别:

XML解析方式SAXDOM
工作原理顺序读入文件并产生相应事件在内存中建立文件树
读取方式只能对文件按顺序剖析一遍可以随意读取文件树的任何部分
可修改性只能读取无法修改可以修改文件树进而修改XML文件
开发难度需要实现事件处理器易于理解和开发
灵活性可用SAX建立自己的XML对象模型已经在DOM基础之上建立了文件树
适用场景1. 处理大型的XML文件
2. 只需XML文件的部分内容
3. 想建立自己的对象模型时
1. 需要对文件进行修改
2. 需要随机对文件进行读取

2 JSON

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

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

结语

本章就整理了这么多关于《图解HTTP》一书中讲述的内容。下面推荐两本书也非常不错的相关书籍:

  • 《HTTP权威指南》
  • 《TCP/IP详解卷1:协议》