Skip to main content

HTTP

HTTP简介#

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议) 的缩写,是用于从万维网 (WWW:World Wide Web) 服务器传输超文本到本地浏览器的传送协议。

HTTP是一个基于TCP/IP通信协议来传递数据 (HTML 文件, 图片文件, 查询结果等)。

HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出。

HTTP协议是由从客户机到服务器的请求(Request)和从服务器到客户机的响应(response)进行约束和规范

TCP/IP 协议栈#

  • 应用层 : 为用户提供各种需要的服务器,例如 :HTTP、FTP、DNS、SMTP等.
  • 传输层:为应用层实体提供端到端的通信功能,保证数据包的顺序传送及数据的完整性。该层定义了两个主要的协议:传输控制协议(TCP)和用户数据报协议(UDP)。
  • 网络层:主要解决主机到主机的通信问题. IP 协议是网际互联层最重要的协议。

HTTP工作原理#

一次HTTP操作称为一个事务,其工作过程可分为四步:

  1. 客户端连接到Web服务器:首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
  2. 发送HTTP请求:建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
  3. 服务器接受请求并返回HTTP响应:服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
  4. 客户端浏览器解析HTML内容:客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。

如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。

URL 和 URI#

URI:统一资源标识符,分为URL和URN两种:

  • URL:统一资源定位符,描述了一台特定服务器 上某资源的特定位置。大部分 URL 都遵循一种标准格式,这种格式包含三个部分:协议、域名、文件地址
  • URN:是作为特定内容的唯一名称使用的,与目前的资源所在地无关. 通过 URN,还可以用同一个名字通过多种网络协议来访问资源。

请求方法#

  • GET 请求获取Request-URI所标识的资源
  • POST 在Request-URI所标识的资源后附加新的数据
  • HEAD 请求获取由Request-URI所标识的资源的响应消息报头
  • PUT 请求服务器存储一个资源,并用Request-URI作为其标识
  • DELETE 请求服务器删除Request-URI所标识的资源
  • TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
  • CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
  • OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求

Request、Response#

http协议的请求和响应,主要有请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。

更多HTTP查看

状态码#

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

  • 1xx:指示信息--表示请求已接收,继续处理
  • 2xx:成功--表示请求已被成功接收、理解、接受
  • 3xx:重定向--要完成请求必须进行更进一步的操作
  • 4xx:客户端错误--请求有语法错误或请求无法实现
  • 5xx:服务器端错误--服务器未能实现合法的请求

::: warning

GET 和 POST 有什么区别?#

差别如下:

  • 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会
  • 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制
  • 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
  • 从幂等性的角度,GET是幂等的,而POST不是。(幂等表示执行相同的操作,结果也是相同的)
  • 从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

:::

常用的请求报头#

  1. Accept请求报头域用于指定客户端接受哪些类型的信息。eg:Accept:image/gif,Accept:text/
  2. htmlAccept-Charset请求报头域用于指定客户端接受的字符集。Accept-Encoding:Accept-Encoding请求报 头域类似于Accept,但是它是用于指定可接受的内容编码。
  3. Accept-Language请求报头域类似于Accept,但是它是用于指定一种自然语言。
  4. Authorization请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服 务器的响应代码为401(未授权),可以发送一个包含Authorization请求报头域的请求,要求服务器对其进 行验证。
  5. Host请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的,发 送请求时,该报头域是必需的。
  6. User-Agent请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器。

常用的响应报头#

  1. Location响应报头域用于重定向接受者到一个新的位置。Location响应 报头域常用在更换域名的时候
  2. Server响应报头域包含了服务器用来处理请求的软件信息。与User- Agent请求报头域是相对应的。
  3. WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息 中,客户端收到401响应消息时候,并发送Authorization报头域请求服 务器对其进行验证时,服务端响应报头就包含该报头域。

实体报头#

请求和响应消息都可以传送一个实体。一个实体由实体报头域和实体正 文组成,但并不是说实体报头域和实体正文要在一起发送,可以只发送 实体报头域。实体报头定义了关于实体正文(eg:有无实体正文)和请 求所标识的资源的元信息。

常用的实体报头#

  • Content-Encoding实体报头域被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的 附加内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码 机制。
  • Content-Language实体报头域描述了资源所用的自然语言。
  • Content-Length实体报头域用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
  • Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。
  • Last-Modified实体报头域用于指示资源的最后修改日期和时间。
  • Expires实体报头域给出响应过期的日期和时间。

cookies与session#

::: warning

  • Cookies是保存在客户端的小段文本,随客户端点每一个请求发送该url 下的所有cookies到服务器端。

  • Session则保存在服务器端,通过唯一的值sessionID来区别每一个用 户。SessionID随每个连接请求发送到服务器,服务器根据sessionID来识 别客户端,再通过session 的key获取session值。

:::

  • Cookie使用
    • 与Cookie相关的HTTP扩展头
      1. Cookie:客户端将服务器设置的Cookie返回到服务器;
      2. Set-Cookie:服务器向客户端设置Cookie;
    • 服务器在响应消息中用Set-Cookie头将 Cookie的内容回送给客户端,客户端在 新的请求中将相同的内容携带在Cookie 头中发送给服务器。从而实现会话的保 持。
  • Session的使用
    • 使用Cookie来实现
    • 使用URL回显来实现

HTTP缓存#

::: warning HTTP缓存机制

缓存会根据请求保存输出内容的副本,例如html页面,图片,文件,当 下一个请求来到的时候:如果是相同的URL,缓存直接使用副本响应访 问请求,而不是向源服务器再次发送请求。优点:

  • 减少相应的延时
  • 减少网络带宽消耗

:::

浏览器缓存#

第一次请求

再次请求

缓存分类#

  • 按缓存位置分:我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache, from disk cachefrom ServiceWorker

    ::: warning from memory cache, from disk cachefrom ServiceWorker。它们的优先级是:(由上到下寻找,找到即返回;加不到继续)

    1. Server Worker
    2. Memory Cache
    3. Disk Cache
    4. 网络请求

    :::

    • memory cache: 是内存中的缓存(相对 disk cache 就是硬盘上的缓存). 几乎所有的网络请求资源都会被浏览器自动加入到 memory cache 。但是也正因为数量很大但是浏览器占用的内存不能无限扩大这样两个因素,memory cache 注定只能是个“短期存储”,也就是 TAB 关闭后 memory cache 便就失效了;memory cache 机制保证了一个页面中如果有两个相同的请求 (例如两个 src 相同的,两个 href 相同的 )都实际只会被请求最多一次,避免浪费;在从 memory cache 获取缓存内容时,浏览器会忽视例如 max-age=0, no-cache 等头部配置,如果不想让一个资源进入缓存,短期也不行,那就需要使用 no-store
    • disk cache:disk cache 也叫 HTTP cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。disk cache 会严格根据 HTTP 头信息中的各类字段来判定哪些资源可以缓存,哪些资源不可以缓存;哪些资源是仍然可用的,哪些资源是过时需要重新请求的。当命中缓存之后,浏览器会从硬盘中读取资源,虽然比起从内存中读取慢了一些,但比起网络请求还是快了不少的。绝大部分的缓存都来自 disk cache。
    • ServiceWorker:Service Worker 能够操作的缓存是有别于浏览器内部的 memory cache 或者 disk cache 的。我们可以从 Chrome 的 F12 中,Application -> Service Workers 找到。除了位置不同之外,这个缓存是永久性的,即关闭 TAB 或者浏览器,下次打开依然还在(而 memory cache 不是)。如果 Service Worker 没能命中缓存,一般情况会使用 fetch() 方法继续获取资源。这时候,浏览器就去 memory cache 或者 disk cache 进行下一次找缓存的工作了。注意:经过 Service Worker 的 fetch() 方法获取的资源,即便它并没有命中 Service Worker 缓存,甚至实际走了网络请求,也会标注为 from ServiceWorker
  • 按失效策略分:

    1. memory cache 是浏览器为了加快读取缓存速度而进行的自身的优化行为,不受开发者控制,也不受 HTTP 协议头的约束,算是一个黑盒。
    2. Service Worker 是由开发者编写的额外的脚本,且缓存位置独立。
    3. disk cache 其实是我们最熟悉也是说的最多的。主要分为强缓存协商缓存

::: warning

如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。

:::

强制缓存与对比缓存#

  • 强制缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。

    浏览器先根据这个资源的http头信息来判断是否命中强缓存。如果命中则先访问缓存数据库看是否存在,如果存在缓存中的资源直接返回,并不会将请求发送到服务器。

    强缓存是利用http的返回头中的 Expires 或者 Cache-Control 两个字段来控制的,用来表示资源的缓存时间。

    • Expires: 缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。如:Expires: Thu, 10 Nov 2017 08:45:11 GMT,在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。 这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当客户端本地时间被修改以后,服务器与客户端时间偏差变大以后,就会导致缓存混乱。于是发展出了Cache-Control。

    • Cache-Control:Cache-Control是一个相对时间,例如Cache-Control:3600,代表着资源的有效期是3600秒。由于是相对时间,并且都是与客户端时间比较,所以服务器与客户端时间偏差也不会导致问题。

      Cache-ControlExpires可以在服务端配置同时启用或者启用任意一个,同时启用的时候 Cache-Control优先级高 。

      ::: warning Cache-Control 可以由多个字段组合而成,主要有以下几个取值:

      1. max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。在没有禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。
      2. s-maxage 同 max-age,覆盖 max-age、Expires,但仅适用于共享缓存,在私有缓存中被忽略。
      3. public 表明响应可以被任何对象(发送请求的客户端、代理服务器等等)缓存。
      4. private 表明响应只能被单个用户(可能是操作系统用户、浏览器用户)缓存,是非共享的,不能被代理服务器缓存。
      5. no-cache 强制所有缓存了该响应的用户,在使用已缓存的数据前,发送带验证器的请求到服务器。不是字面意思上的不缓存。
      6. no-store 禁止缓存,每次请求都要向服务器重新获取数据。
      7. must-revalidate 指定如果页面是过期的,则去服务器进行获取。这个指令并不常用,就不做过多的讨论了。

      :::

  • 比较缓存,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由 服务器校验,返回304状态码时,浏览器直接使用缓存。(协商缓存)

    • Etag/If-None-Match策略

      Etag 返回的是一个特殊标识(一般都是 hash 生成). Etag 可以保证每一个资源是唯一的,资源变化都会导致 Etag变化。ETag值的变更则说明资源状态已经被修改。服务器根据浏览器上发送的 If-None-Match 值来判断是否命中缓存。命中缓存返回 304,不命中返回新资源 200

    • Last-Modified/If-Modified-Since

      若未命中强缓存,则浏览器会将请求发送至服务器。服务器根据 http 头信息中的 Last-Modified/If-Modify-SinceEtag/If-None-Match来判断是否命中协商缓存。如果命中,则http返回码为304,浏览器从缓存中加载资源。其主要步骤如下:

      1. 浏览器第一次请求一个资源的时候,服务器返回的header中会加上 Last-Modified 是一个时间标识该资源的最后修改时间,例如:Last-Modified:Thu,31 Dec 2037 23:59:59 GMT。
      2. 浏览器将这个值和内容一起记录在缓存数据库中
      3. 当浏览器再次请求该资源时,发送的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modified。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。
      4. 如果命中缓存,则响应 304,并且不会返回资源内容,并且不会返回Last-Modified。由于对比的服务端时间,所以客户端与服务端时间差距不会导致问题。但是有时候通过最后修改时间来判断资源是否修改还是不太准确(资源变化了最后修改时间也可以一致)。于是出现了 ETag/If-None-Match

浏览器行为#

所谓浏览器的行为,指的就是用户在浏览器如何操作时,会出发怎样的缓存策略,有以下三种:

  1. 打开网页,输入地址:查找 disk cache 中是否匹配. 如有则使用;如没有则发送网络请求
  2. 普通刷新(F5):因为 TAB 没有关闭,根据上面所说浏览器会自动缓存一些资源, 因此 memory cache 是可用的,会被优先使用(如果配置的话),其次才是 disk cache
  3. 强制刷新(Ctrl + F5): 浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(为了兼容,还带了 Pragma: no-cache)。服务器直接返回 200 和最新内容。

http1和http2的区别#

​ 早在HTTP建立之初,主要就是为了将超文本标记语言(HTML )文档从Web服务器传送到客户端的浏览器。也是说对于前端来说,我们所写的HTML页面将要放在我们的web服务器上,用户端通过浏览器访问url地址来获取网页的显示内容,但是到了WEB2.0以来,我们的页面变得复杂,不仅仅单纯的是一 些简单的文字和图片,同时我们的HTML页面有了CSS, Javascript, 来丰富我们的页面展示,当ajax 的出现,我们又多了-种向服务器端获取数据的方法,这些其实都是基于HTTP协议的。同样到了移动互联网时代,我们页面可以跑在手机端浏览器里面,但是和PC相比,手机端的网络情况更加复杂,这使得我们开始了不得不对HTTP进行深入理解并不断优化过程中。

  • 1991 Http/0.9
  • 1996 Http/1.0
  • 1999 Http/1. 1
  • 2015 Http/2

Http1.0和Http1.1 区别#

HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1. 1则在999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。主要区别主要体现在 :

  • 缓存处理,在HTTP1.0中主要使用header里的lf-Modified- Since, Expires来 做为缓存判断的标准,HTTP1. 1则引入了更多的缓存控制策略例如Entity tag, If-Unmodified- Since, If-Match,lf-None Match等更多可供选择的缓存头来控制缓存策略。
  • 带宽优化及网络连接的使用,HTTP1.0中, 存在一些浪费带 宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1. 1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206 (Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  • 错误通知的管理,在HTTP1. 1中新增了24个错误状态响应码,如409 (Conflict) 表示请求的资源与资源的当前状态发生冲突; 410 (Gone)表示服务器上的某个资源被永久性的删除。
  • Host头处理,在HTTP1. 0中认为每台服务器都绑定一个唯一 的IP地址,因此,请求消息 中的URL并没有传递主机名(hostname)。但随着 虚拟主机技术的发展, 在-台物理服务器 上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享个IP地址。 HTTP1.1的请求消息和响应消息都应支持Host头域, 且请求消息中如果没有Host头域会报告-个错误 (400 Bad Reques)。
  • 长连接,HTTP 1. 1支持长连接(PersistentConnection) 和请求的流水线(Pipelining) 处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive ,一 定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

SPDY: HTTP1.x的优化#

2012年google如一声惊雷提出了SPDY的方案,优化了HTTP1.X的请求延迟,解决了HTTP1.X的安全性,具体如下:

  • 降低延迟,针对HTTP高 延迟的问题,SPDY 优雅的采取了多路复用(multiplexing) 。多路复用通过多个请求stream共享-个tcp连接的方式,解决了HOL blocking的问题,降低了延迟同时提高了带宽的利用率。
  • 请求优先级(request prioritization) 。多路复用带来一个新的问题是, 在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY 允许给每个request设置优先级,这样重要的请求就会优先得到响应。比如浏览器加载首页,首页的html内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第时间看 到网页内容。
  • header压缩。前面提到HTTP1. x的header很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量。
  • 基于HTTPS的加密协议传输,大大提高了传输数据的可靠性。
  • 服务端推送(server push) ,采用了SPDY的网页,例如我的网页有一个sytle .css的请求,在客户端收到sytle .css数据的同时,服务端会将sytle .js的文件推送给客户端,当客户端再次尝试获取sytle .js时就可以直接从缓存中获取到,不用再发请求了。

Http2.0 SPDY的升级版#

HTTP2.0可以说是SPDY的升级版(其实原本也是基于SPDY设计的),但是,HTTP2.0 跟SPDY仍有不同的地方,如下: HT TP2.0和SPDY的区别:

  • HTTP2.0支持明文HTTP传输,而SPDY强制使用HTTPS
  • HTTP2.0消息头的压缩算法采用HPACK, 而非SPDY采用的DEFL ATE

Http2.0和http1.X 相比的新特性#

新的二进制格式(Binary Format)#

HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用一进制格式,实现方便且健壮。

多路复用(MutiPlexing)#

在说多路复用之前,先说一下在http2中有两个概念,分别是stream(流) 和frame(帧) ,frame 是 最小的单位,每个frame会有Stream Identifier 来标示它是属于哪个stream的。

在http1.x情况下,每个http请求都会建立一个tcp连接,也就意味着每个请求都要进行三次握手,这会造成时间和资源的浪费,而且浏览器会限制同一域名下并发请求的个数,当请求很多资源时,队头阻塞会导致在达到最大请求数量时,剩余的资源要等待其他资源请求完成才能发起请求(这里可以引申一下针对此种情况的优化手段,就是把不同资源放在不同域名下,以此来突破浏览器最大并发数的限制)。

在http2的情况下,所有的请求都会共用一个tcp连接,就可以传输所有的请求数据。这就解决了浏览器同一域名请求数量的问题,也解决了每开一个tcp 连接都会造成的资源时间浪费。

同一个tcp连接下多个http请求,如何保证传输不出错呢?

这就要用到开始提到的两个概念了,多路复用,就是在一个tcp连接中可以存在多个stream ,也就是多个请求,每个stream 又包含了多个frame ,通过StreamIdentifier就可以识别出每个 frame 分别对应的stream,当frame 到达服务端之后,就可以根据Stream Identifier 来重新组合得到完整的请求了,这就在提高传输性能的同时保证了传输的正确性。 简单来说: 多路复用(MultiPlexing) ,即连接共享,即每个request都 是是用作连接共享机制的。一个request对应一个id,这样个连接 上 可以有多个request,每个连接的request可以随机的混杂在一起, 接收方可以根据request的id将request再归属 到各自不同的服务端请求里面。

Header 压缩#

http1.x中,使用文本的形式传输header每次请求都会带上,这些基本上都是不变的,如果再加上cookie的话也是不小的浪费。

http2中,使用了HPACK 压缩格式对header 进行了编码,减少了header 的大小,大概原理就是在服务端和客户端共同维护一个静态字典,用于记录出现过的header后面在传输过程中发送端直接传输已经记录过的键名,接收端就可以通过键名找到对应的值。 简洁点就是: HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2 . 0使用encoder来减少需要传输的header大小,通讯双方各自cache-份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

服务端push#

在http2 中,服务端可以在客户端的某个请求后,根据这个请求,主动推送其他的资源。

比如一个html页面中还带上可一个css和js的资源请求,http1.x 时,要发送三次请求,在http2中,不用请求三次,服务器发现html中包含了css 和js资源,便会将三个资源都返回给客户端,这样只需要一次通信, 就可以获得全部资源。

扩展#

HTTP2.0的多路复用和HTTP1.X中的长连接复用有什么区别?#

  • HTTP/1.* 一次请求一响应,建立一个连接,用完关闭;每一个请求都要建立 一个连接;
  • HTTP/1.1 Pipeling 解决方式为, 若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;
  • HTTP/2多个请求可同时在一 个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;

服务端推送到底是什么#

服务端推送能把客户端所需要的资源伴随着index.html-起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。

什么需要头部压缩?#

假定一个页面有100个资源需要加载(这 个数量对于今天的Web而言还是挺保守的),而每一次请 求都有1kb的消息头(这同样也并不少见,因为Cookie和引用等 东西的存在),则至少需要多消耗100kb来获取这些消息头。HTTP2.0可以维护一个字典,差量更新HTTP头部,大大降低因头部传输产生的流量。

HTTP2.0多路复用有多好#

HTTP性能优化的关键并不在于高带宽, 而是低延迟。TCP连接会随着时间进行自我「调谐」,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为TCP慢启动。由于这种原因,让原本就具有突发性和短时性的HTTP连接变的十分低效。HTTP/2 通过让所有数据流共用同一个连接,可以更有效地使用TCP连接,让高带宽也能真正的服务于HTTP的性能提升。

其他#

三次握手#

握手使用了 TCP 的标志 SYNACK,其主要步骤如下:

  1. 发送端首先发送一个带 SYN标志的数据包给对方.
  2. 接收端收到后,回传一个带有 SYN/ACK 标志的数据包以表示传达确认信息。
  3. 最后发送端再回传一个带有 ACK 标志的数据包,代表 握手 结束

::: warning 为什么要进行三次握手?

  • 在发送报文之前客户端和服务端都要确认可以进行连接. 之所以进行三次握手,是为了信息传输的可靠性,如果其实某个握手失败,这个过程会重复
  • 如果采用两次握手,相当于第二次握手结束便建立连接。如果 客户端一方不想连接了,也不会有反馈,则客户端一直在等待,浪费时间。当然也可以建立4次,不过建立次数太多,建立连接的时间太长,效果也会大打折扣。所以3次只是折中方案,保证了可靠性,又节俭了建立连接的时间。

如在握手过程中某个阶段莫名其妙的中断,TCP 协议会再次以相同的顺序发送相同的数据包

:::

四次挥手#

  1. 客户端发送 Fin+Ack 报文,表示关闭数据传输,发送端进入 FIN_WAIT 状态,表示没有数据要传输了
  2. 服务端收到 FIN 报文后进入 CLOSE_WAIT 状态(被动关闭),然后发送 ACK确定,表示同意关闭请求,客户端进入到 FIN_WAIT_2
  3. 服务端等待数据发送完,再次发送 FIN 到客户端 请求关闭,服务端进入 LAST_ACK 状态
  4. 客户端收到服务端发送的 FIN 后,回复 ACK 到服务端,客户端进入 TIME_WAIT.状态 服务端接受到客户端发送的 ACK后就关闭连接,状态为 CLOSED. 客户端等待 2MSL 没有收到服务端的回复,说明服务端已经正常关闭了,服务端关闭连接。

::: warning 为什么客户端发送 ACK 后要等待 2MSL 而不是直接关闭

  • 保证客户端发送的 ACK 报文能够到达服务器,从而保证 tcp 能够可靠的关闭 如果客户端发送完马上关闭,一旦 ACK 丢失,服务端就会一直处于等待关闭确认的状态, 超时后再次发送关闭请求,此时客户端已经关闭,服务端无法进行正常的关闭
  • 保证此次连接的数据段消失,防止失效的数据段

客户端在发送ACK后,再等待2MSL时间,可以使本次连接所产生的数据段从网络中消失,从而保证关闭连接后不会有还在网络中滞留的数据段去骚扰服务端;

  • 2MSL的等待时间

我们知道服务端收到ACK,关闭连接。但是客户端无法知道ACK是否已经到达服务端,于是开始等待?等待什么呢?假如ACK没有到达服务端,服务端会为FIN这个消息超时重传 timeout retransmit ,那如果客户端等待时间足够,又收到FIN消息,说明ACK没有到达服务端,于是再发送ACK,直到在足够的时间内没有收到FIN,说明ACK成功到达。这个等待时间至少是:服务端的timeout + FIN的传输时间,为了保证可靠,采用更加保守的等待时间2MSL。 :::

浏览器输入url到加载页面经过了什么?#

  1. 输入网址并回车
  2. 解析域名
  3. 浏览器发送HTTP请求
  4. 服务器处理请求
  5. 服务器返回HTML响应
  6. 浏览器处理HTML页面
  7. 继续请求其他资源