深刻理解网络协议之HTTP

超文本传输协议(HyperText Transfer Protocol), 是一种用于分布式、协做式和超媒体信息系统的应用层协议, 是万维网的数据通讯的基础(维基百科)。这里咱们主要关注一下什么是应用层,以及网络是如何分层的.html


网络的分层

网络为何要分层[1]?web

  1. 各层之间相互独立, 某一层并不须要知道它下一层是如何实现的,而仅仅须要知道该层经过层间的接口所提供的服务。因为每一层只实现一种相对独立的功能,于是能够将一个难以处理的复杂问题分解为若干个较容易处理的更小问题,这样,整个问题的复杂度就降低了。
  2. 灵活性, 当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或如下各层均不受影响,此外,对某一层提供的服务还能够进行修改。当某层提供的服务再也不须要时,甚至能够将这层取消
  3. 结构上可分割开。各层均可以采用最合适的技术来实现。
  4. 易于实现和维护。这种结构使得实现和调试一个庞大而又复杂的系统变得易于处理,由于整个系统已被分解为若干个相对独立的子系统。
  5. 能促进标准化工做。由于每一层的功能及其所提供的服务都已有了精确的说明。

OSI七层模型

开放式系统互联通讯参考模型,由国际标准化组织提出。
OSI将网络分为七层: 应用层、表示层、会话层、传输层、网络层、链路层、物理层。算法

TCP/IP五层模型

TCP/IP是实际的标准, 分为五层: 应用层、传输层、网络层、链路层、物理层。浏览器

TCP/IPOSI的分层的对应关系, 以下图所示:
缓存

TCP/IP与OSI

TCP/IP也能够说是四层, 若是是四层的话就是把链路层物理层统称为网络接口层安全


HTTP的过程

让咱们从一次请求过程来了解HTTPbash

请求的准备

  1. 在输入URL以后,首先须要DNS来将域名解析为IP地址。
  2. 创建TCP链接(三次握手),创建链接的时候是须要发送IP包的。
  3. 若是是HTTPS会进行TLS/SSL的握手。

请求的构建

链接创建之后,就是要向服务器发送请求,那么请求格式是怎么样的呢? HTTP1.1为明文传输,因此咱们很容易可以在ChromeNetwork中看到,请求的格式以下图所示:
服务器

HTTP请求格式

从上图能够看出,请求分为了三部分:请求行,首部,实体。websocket

首部与实体之间使用空行分隔。网络

请求行

请求行由三部分构成:方法,URLHTTP版本号,以空格隔开。

方法

主要的方法有:GET POST OPTIONS HEAD

GET

若是有参数,会将其放在URL中: 优势:

  1. 请求的URL能够被缓存
  2. 能够手动输入,并保存参数
  3. 相对较快(会在TCP第三次握手时将报文随握手包发送)。 缺点:
  4. 参数有大小限制(受限于URL的长度)
  5. 参数可见,相对不安全

GET请求的过程[2]:

  1. 浏览器请求TCP链接(第一次握手)
  2. 服务器答应进行TCP链接(第二次握手)
  3. 浏览器确认,并发送GET请求头和数据
  4. 服务器返回200 OK响应
POST

参数存在于实体中: 优势:

  1. 能发送更多的数据。
  2. 参数不直接可见,相对安全(相对GET,抓包除外)。 缺点:
  3. 相对较慢(在首部中相对GET多了几个用于协商的首部,且须要待第三次握手后再发送报文)。

POST请求的过程[2]:

  1. 浏览器请求TCP链接(第一次握手)
  2. 服务器答应进行TCP链接(第二次握手)
  3. 浏览器确认,并发送POST请求头(第三次握手)
  4. 服务器返回100 Continue响应
  5. 浏览器发送数据
  6. 服务器返回200 OK响应
OPTIONS

CORS 中预检请求

HEAD

请求资源的首部信息, 而且这些首部与GET方法请求时返回的一致。响应不该包含响应实体,即便包含了实体也必须忽略掉。

URL

URL(Uniform Resource Locator), 统一资源定位符, 是因特网上标准的资源的地址。

完整格式:协议类型:[//[访问资源须要的凭证信息@]服务器地址[:端口号]][/资源层级UNIX文件路径]文件名[?查询][#片断ID]

另外,与URL相关的定义还有URIURNURI(Uniform Resource Identifier),统一资源标识符,用于标识某一互联网资源名称的字符串。 URN(Uniform Resource Name),统一资源名称,一种为资源提供持久的、位置无关的标识方式。

URLURNURI的子集,三者关系,以下图所示:

URL, URN, URI

举个栗子:urn:isbn:0-486-27557-4这是一个资源,它是URN,也是URI,但不是URL

HTTP 版本

主要版本:0.九、1.0、1.12

首部

首部是key: value形式,经过冒号空格分隔,为客户端和服务器分别处理请求和相应提供所须要的信息。 首部分为四类:请求首部,响应首部,通用首部,实体首部。

请求首部

顾名思义,只会在请求报文中存在。

  1. Accept-Charset:客户端支持的字符集,例:utf-8
  2. Accept-Encoding:客户端能够接受的内容编码形式,例:gzip
  3. Referer:对请求中URL的原始获取方。
  4. Host:请求资源所在服务器。
  5. ......

通用首部

  1. Accept-Language:提示用户指望得到的天然语言的优先顺序。
  2. User-Agent:用来识别发送请求的浏览器。
  3. Cache-Control:缓存控制。
  4. ......

实体首部

  1. Content-Encoding:实体的编码方式。
  2. Content-Language:实体的天然语言。
  3. Content-Type:实体的媒体类型。
  4. ......

响应首部

  1. Location:令客户端重定向至指定URL
  2. Retry-After:对再次发起请求的时机要求。
  3. ServerHTTP服务器的安装信息。
  4. ETag:资源匹配信息(缓存相关)。
  5. ......

一切准备完成后就是发送请求。

请求的发送与接收

请求发送接收的过程以下图所示:

请求的发送

请求的发送

  1. 浏览器将HTTP构建完成后,经过网络线程将请求报文交给TCP
  2. TCP将请求的报文进行分割,并将各个报文包入TCP的头部,交给IP
  3. IPTCP报文包入IP的头部,交个链路层。
  4. 链路层报上以太网首部经过物理层发送报文(待后续补充)。

请求的接收

  1. 网卡接收到请求后,会先查看目标MAC地址是否为本身的MAC地址,若是是会把以太网头部去除,交个上层协议。
  2. IP收到链路层发送的数据后,会检查目标IP是否为本身的IP,若是是把IP头部去除,交给上层协议。
  3. TCP收到数据后,去掉TCP头部,交给浏览器。

请求的响应

响应的构建

响应的格式

响应与请求除了状态行外结构基本相同,一样分为 3 部分:状态行,首部,实体。

状态行

状态行分为 3 部分:HTTP版本,状态码,短语,以空格分隔,其中短语为对状态码的解释。

状态码

状态码分类

主要状态码介绍
  1. 200 OK:表示从客户端发送来的请求在服务器端被正常处理了。对应请求资源的实体主体随报文首部做为响应返回(HEAD 方法不会返回实体,即便返回也会被忽略)。
  2. 204 Not Content:服务器接收的请求已成功处理,可是再返回的响应报文中不包含实体的主体部分。另外,也不容许返回任何实体的主体。(MDN:使用惯例是,在PUT 请求中进行资源更新,可是不须要改变当前展现给用户的页面,那么返回204 No Content。例如:提交表单后,不进行页面跳转)。
  3. 206 Partial Content:客户端进行了范围请求,而服务器成功执行了这部分的GET请求。响应报文中包含由Content-Range指定范围的的实体内容。
  4. 301 Moved Permanently:永久重定向,表示请求的资源已被分配了新的URL,之后请使用资源如今所指的URL。搜索引擎会根据该响应修正。
  5. 302 Found:临时重定向,表示请求的资源已被分配了新的URL,但愿用户(本次)能使用新的URL访问。已改变,且未来还有可能发生改变。
  6. 303 See Other:请求对应的资源存在着另外一个URL,应使用GET方法定向获取请求的资源。(301302303响应状态码返回时几乎全部的浏览器都会把POST改为 GET,并删除请求报文的主体,以后请求会自动再次发送。)。
  7. 304 Not Modified:服务器端资源未改变,可直接使用客户端未过时的缓存,返回结果不包含任何响应的主体部分。
  8. 307 Temporary Redirect:临时重定向。与302之间的惟一区别在于,当发送重定向请求的时候,307状态码能够确保请求方法和消息主体不会发生变化。
  9. 400 Bad Request:请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像200 OK同样对待该状态码。
  10. 401 Unauthorized:表示因为缺少目标资源要求的身份验证凭证,发送的请求未获得知足。这个状态码会与WWW-Authenticate首部一块儿发送,其中包含有如何进行验证的信息。
  11. 403 Forbidden:表示服务器端有能力处理该请求,可是拒绝受权访问(无权限)。
  12. 404 Not Found:表示服务器上没法找到请求的资源。
  13. 500 Internal Server Error:表示服务器端在执行请求时发生了错误,也有多是 Web 应用存在的 Bug 或某些临时的故障。
  14. 503 Service Unavailable:表示服务器暂时处于超负载或正在进行停机维护,如今没法处理请求。若是事先得知解除以上情况须要的时间,最好写入Retry-After首部字段再返回给客户端。

在完成了响应的构建以后,会按照与发送相同的方式将响应发送给客户端。最后TCP四次回收断开链接。

整个请求过程以下图所示:

HTTP请求过程


HTTP版本

HTTP/0.9 单行协议

HTTP/0.9很是简单,请求仅由单行构成,以惟一可用方法GET开头,其后跟目标资源的路径。

GET /index.html

响应也很是简单仅包含响应文档自己,若是出现错误会将错误信息以文档形式返回。

HTTP/1.0 构建可扩展性

主要引入了头部,及状态码,并支持多种文件格式。

HTTP/1.1 标准化的协议

HTTP/1.1 相对 1.0 的不一样:

  1. 持久链接:默认都开启了Keep-Alive,全部链接都被保持,除非在请求头或响应头中指明要关闭:Connection: CloseKeep-Alive不会永久保持链接,它有一个保持时间,能够在不一样的服务器软件中设定这个时间(实际是在1.0版本引入,但并不会默认开启)。
  2. 管线化:无需等待上次请求返回也可直接发送下一个请求(实际使用受限,浏览器默认不开启)。
  3. 缓存:增长了新的缓存控制首部,如:Cache-Control等。
  4. Host:请求头指明了服务器的域名(对于虚拟主机来讲),以及(可选的)服务器监听的TCP端口号。
  5. 内容协商机制: 包括语言,编码,类型等,并容许客户端和服务器之间约定以最合适的内容进行交换。

HTTP/2 为了更优异的表现

HTTP/1.1的区别:

  1. 二进制协议:在不改变方法,首部的基础上,转换为二进制协议,称为二进制分帧层。
  2. 多路复用:即在一个TCP链接中能够同时发送多个请求。
  3. 流控制:是一种阻止发送方向接收方发送大量数据的机制,以避免超出后者的需求或处理能力:发送方可能很是繁忙、处于较高的负载之下,也可能仅仅但愿为特定数据流分配固定量的资源。
  4. 服务端推送:服务端推送,服务器能够对一个客户端请求发送多个响应。
  5. 头部压缩。

缓存控制

浏览器在首次对资源进行请求时,会记录缓存相关的首部,在后续请求中根据记录的首部进行相应的资源读取操做,如读取缓存,资源验证等。 缓存的做用:减小请求次数,减小带宽;增长加载速度,减小白屏时间。

在说明缓存控制原理以前,先了解下缓存相关的首部。

缓存相关首部

Cache-Control

控制缓存的有效时间,及缓存行为。
主要值:

  1. max-age:缓存有效时间,即从相应时间后多长时间缓存过时。
  2. no-cache:不缓存,并不是不对资源进行缓存,而是每次请求都须要向源资源服务器验证资源。
  3. no-store:禁止缓存,禁止浏览器对资源进行缓存,每次请求都要从新请求资源。
  4. public:容许全部用户缓存,包括浏览器,代理服务器等。
  5. private:仅容许单个用户缓存,不容许代理服务器缓存。
  6. ......

对于 Cache-Control: no-cache, max-age=900 这种状况,no-cache 与 max-age 的优先级与前后顺序有关。

Expires

HTTP/1.0提出,表示缓存过时时间,超过这个时间即缓存过时。若是响应中有max-ages-maxage会被覆盖。

expires: Sun, 02 Sep 2018 14:36:18 GMT

Last-modified

资源的最后修改时间,主要用于在服务器验证缓存是否被修改时使用。

last-modified: Fri, 18 May 2018 01:10:24 GMT

ETag

资源实体标识,由服务器分配,资源更新时ETge随之改变,分为ETagETag。 **弱ETag**很容易生成,但不利于比较。**强ETag**是比较的理想选择,但很难有效地生成。

ETag: W/"5a323f72-152"(弱) ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"(强)

缓存请求过程

  1. 判断该资源是否有缓存。
  2. 若有缓存,判断缓存是否过时,若是缓存没过时,直接读取缓存,状态码200 (from memory/disk cache)
  3. 若是缓存过时,判断是否有ETagLast-Modified,若是存在,则在请求首部中发送对应的首部If-None-MatchIf-Modified-Since,若是没有则不发送这两个首部。
  4. 服务器端接收到请求后,判断根据If-None-MatchIf-Modified-Since来比较资源的ETag若是改变了比较Last-Modified,若是匹配则返回304,若是不匹配,将资源随实体返回,状态码200

from memory cache 与 from disk cache 为 Chrome 的缓存优化机制,但对于该采用什么方式,并无找到明确答案。

强缓存与协商缓存

强缓存:不会向服务器发送请求,直接读取缓存的方式,在上述过程当中直接返回状态码200 (from memory/disk cache)。 协商缓存:请求资源时会向服务器发送If-None-MatchIf-Modified-Since(若是存在ETagLast-Modified),服务器验证后,返回304200

HTTPS

在学习HTTPS以前,咱们了解下HTTP的缺点:

  1. 明文通讯(不加密),不安全。
  2. 不验证通讯方身份,可能遭遇假装。
  3. 没法保证报文的完整性,可能在途中遭到了篡改。

HTTPS解决了上述缺点(HTTPS并不是新协议,而是HTTP + TLS

对称加密

发送端和接收端使用相同的密钥。发送端使用密钥加密明文,接收端接收后使用密钥解析加密信息,获得明文。
对称加密最大的问题就是在一对多的时候的密钥传输问题,因此为了保证安全对称加密的密钥是绝对不能公开的。

非对称加密

非对称加密有两个密钥,一个是公钥,一个是私钥,公钥加密后的密文只能使用私钥解密,私钥加密后的密文只能使用公钥解密。那么只须要对外展现公钥就能够了。
可是,非对称加密的解密过程速度较慢(对称加密主要是位运算,而非对称加密包含了不少乘法或大数模)。

混合加密

充分利用对称及非对称加密的优点,使用非对称加密的方式传输对称加密的密钥,即有非对称加密的安全又有对称加密的速度。 HTTPS(或者说TLS)就是采用了这种方式。

证书与CA

在拿到公钥后,能不能就直接肯定这个公钥是值得信任的?答案是确定不能,若是公钥是某个黑客伪造的,他就能够修改从发送端接到的请求,在发给服务器了。因此,在拿到公钥后,首先要验证公钥是否是能够信任的,那么谁能保证公钥是能够信任的,那就必需要是一个你信任的机构,这个机构就是CA,而每一个站点的公钥实际都是由CA签发的。因此CA能够验证公钥是否属于这个站点的。

签发及验证过程

  1. 服务器将公钥交给CA
  2. CA使用本身的私钥向服务器的公钥部署数字签名,并颁发公钥证书
  3. 客户端在接收到公钥证书后,客户端使用本身信任的CA的公钥(存在于客户端证书信任列表中)去验证签名是否与公钥匹配。
  4. 若匹配则认为公钥是能够信任的。

链接过程

  1. TCP三次握手后,客户端发送请求安全链接(Client Hello),报文中包含一个随机字符串,并列出客户端支持的加密套件,用于协商对称加密的加密方式。
  2. 服务器端回复(Server Hello),报文中包含服务端选择的加密方式;同时将证书和公钥发送给客户端,同时报文中包含一个随机字符串;最后发送完成握手协商结束(Server Hello Done)。
  3. 客户端接收到证书后,根据证书上的CA,使用该CA的公钥解密证书,来验证公钥是否安全,若是CA的证书由上级CA提供且不在信任列表内,则须要一直向上找到客户端信任的CA为止。
  4. 验证公钥安全后,客户端会使用公钥加密并发送一段叫作Pre-master secret的随机字符串,客户端及服务器端使用上面提到的三个随机字符串,并使用协商好的加密算法计算出对称加密的密钥。
  5. 客户端发送Change Cipher Spec报文,以提示服务器后续通讯将采用计算好的对称加密密钥进行通讯
  6. 客户端继续发送Finished报文,报文中包含链接至今所有报文的总体校验值,若是服务器端可以正确解密该报文,则握手成功
  7. 服务器端发送Change Cipher Spec报文
  8. 服务器端发送Finished报文,链接创建。

WebSocket

WebSocket是能够实现客户端与服务器端双向通讯的新协议,除了借助HTTP完成一次握手外,与HTTP没有关系。

链接过程

  1. TCP三次握手。
  2. 客户端发送升级请求,请求首部以下:
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
复制代码

上述首部中主要是用到了Upgrade首部,用于通知服务器切换协议到WebSocket。 3. 服务器端接收到升级协议的请求后,若是支持WebSocket会响应该请求。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
复制代码

响应状态码:101,表示服务器端应客户端升级协议的请求正在升级协议。 4. WebSocket握手完成,后续通讯将使用WebSocket协议。

参考:
[1]《计算机网络(第五版)》(谢希仁)
[2] http GET 和 POST 请求的优缺点、区别以及误区
[3] TLS 握手优化详解

相关文章
相关标签/搜索