HTTP初探

Posted by Mathew on 2016-08-21

The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, hypermedia information systems. HTTP is the foundation of data communication for the World Wide Web.

Hypertext is structured text that uses logical links (hyperlinks) between nodes containing text. HTTP is the protocol to exchange or transfer hypertext.

Development of HTTP was initiated by Tim Berners-Lee at CERN in 1989. Standards development of HTTP was coordinated by the Internet Engineering Task Force (IETF) and the World Wide Web Consortium (W3C), culminating in the publication of a series of Requests for Comments (RFCs). The first definition of HTTP/1.1, the version of HTTP in common use, occurred in RFC 2068 in 1997, although this was obsoleted by RFC 2616 in 1999.

A later version, the successor HTTP/2, was standardized in 2015, and is now supported by major web servers.

HTTP发展史

HTTP/0.9

最早版本是1991年发布的0.9版。该版本极其简单。只支持简单的HTML格式的字符串传送。

HTTP/1.0

1996年5月,HTTP/1.0发布,新增MIME机制。支持了任何格式的内容传送。包括文字、图片、视频、二进制文件等。 为互联网的猛速发展奠定了基础。

HTTP/1.1

1997年1月,HTTP/1.1发布。
  1. 持久连接
    HTTP1.1的最大变化,就是引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明 Connection:keep-alive。
  2. 管道机制
    HTTP1.1版本引入管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求,但是服务器还是按照顺序依次响应请求。 进一步改进了HTTP协议的效率。
  3. Centent-Length 字段
    一个TCP连接现在可以传送多个回应,那么就要有一种机制来区分数据包是属于哪一个回应的。 这就是Content-Length字段的作用,声明本次回应的数据长度。
1
Content-Length: 3698
 表示告诉浏览器,本次回应的长度是3698个字节,后面的字节就属于下一个请求回应的。
  1. 分块传输编码
    使用Content-Length字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。
    对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。
    因此,1.1版规定可以不使用Content-Length字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。
    Transfer-Encoding: chunked
    每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。下面是一个例子。
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
25
This is the data in the first chunk
1C
and this is the second one
3
con
8
sequence
0
  1. 其他功能
    HTTP1.1版本还新增了许多方法:PUT、PATCH、HEAD、OPTIONS、DELETE。并新增了Host字段,用来指定服务器的域名。
  2. 不足
    虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。
    为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等等。如果HTTP协议设计得更好一些,这些额外的工作是可以避免的。

SPDY协议

2009年,谷歌公开了自行研究的SPDY协议,主要结局HTTP/1.1效率不高的问题。该协议为HTTP/2奠定了基础。

HTTP/2

2015年,HTTP/2发布。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1.二进制协议 
HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。

2. 多工模式
HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"
举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
这样双向的、实时的通信,就叫做多工(Multiplexing)。

3. 数据流
因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。

4. 头部信息压缩
HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。
HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。

5. 服务器推送
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。
常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。

一次完整的http请求处理的过程

1
2
3
4
5
6
7
1. 建立或处理连接:接收请求或拒绝请求
2. 接收请求:接收来自于网络的请求报文中对某资源的一次请求的过程
3. 处理请求:对请求报文进行解析,并获取请求的资源及请求方法等相关信息
4. 访问资源:获取请求报文中请求的资源
5. 构建响应报文
6. 发送响应报文
7. 记录日志

httpd的特性

1
2
3
1. 高度模块化:core + modules 核心 + 模块
2. DSO(Dynamic Shared Object) 支持动态装卸载
3. MPM:Multipath Processing Modules 多处理模块

MPM的实现方式

1
2
3
4
5
6
1. perfork:多进程模型,每个进程相应一个请求;
一个主进程:负责生成n个子进程,子进程也称为工作进程,每个子进程处理一个用户请求;即便没有用户请求,也会预先生成多个空闲进程,随时等待请求到达;最大不超过1024个。
2. worker:多线程模型,每个线程相应一个请求;
一个主进程:生成多个子进程,每个子进程负责生成多个线程,每个线程响应一个请求; m进程,n线程:m*n
3. event:事件驱动模型,每个线程响应n个请求;
一个主进程:生成m个子进程,每个进程直接响应n个请求。 m*n

httpd的功能特性

1
2
3
4
5
6
7
1. 虚拟主机
2. CGI:Common Gateway Interface,通用网关接口。
3. 反向代理
4. 负载均衡
5. 路径别名
6. 丰富的用户认证机制
7. 支持第三方模块