标签: http

当我们的页面发起资源请求时,浏览器会通过缓存等手段来尽快响应,避免不必要的http消耗,所以我们经常见到:Memory Cache、Disk Cache、Push Cache,现在又多了一种ServiceWorker。我们来简单对比如下:

ServiceWorker

Service worker是一个注册在指定源和路径下的事件驱动worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。Service Worker 可以使你的应用先访问本地缓存资源,包括js、css、png、json等多种静态资源。

当我们启用ServiceWorker时,浏览器就会显示我们的资源来自ServiceWorker。Service Worker的缓存有别与其他缓存机制,我们可以自由控制缓存、文件匹配、读取缓存,并且是持续性的。当ServiceWorker没有命中时才会去重新请求数据。

因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 传输协议来保障安全 它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。

Service Worker 实现缓存功能的三个步骤:

    • 首先需要注册 Service Worker
    • 然后监听 install 事件后就可以缓存需要的文件
    • 最后在下次用户访问的时候,通过拦截请求的方式查询是否存在缓存,如果存在就直接读取缓存文件否则就去请求数据

特点:

  1. 独立于主JavaScript线程(这就意味着它的运行丝毫不会影响我们主进程的加载性能)
  2. 设计完全异步,大量使用Promise(因为通常Service Worker通常会等待响应后继续,Promise再合适不过了)
  3. 不能访问DOM,不能使用XHR和localStorage
  4. Service Worker只能由HTTPS承载(出于安全考虑)

详见:前端缓存之:Service Worker | 码农备忘录 (zuifengyun.com)

当 Service Worker 没有命中缓存的时候,我们需要去调用 fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。

Memory Cache

Memory Cache为内存中的缓存,读取内存中的资源是非常快的。 是浏览器为了加快读取缓存速度而进行的自身的优化行为,不受开发者控制,也不受 HTTP 协议头的约束。内存读取虽然快且高效,但它是短暂的,当浏览器或者tab页面关闭,内存就会被释放了。而且内存占用过多会导致浏览器占用计算机过大内存。

  • 内存中的缓存:读取高效、持续时效短,会随着进程的释放而释放
  • 在缓存资源时并不关心返回资源的请求头 Cache-Control 的值是什么,同时资源的匹配也并非仅仅是对 URL 做判断,还可能会对 Content-Type、Cors 等其他特征做校验
  • 普通刷新 F5 操作,优先使用 Memory Cache

Disk Cache

Disk Cache 将资源存储在硬盘中,读取速度次于Memory Cache。

优点:可长期存储,可定义时效时间、容量大;缺点:读取速度慢。

根据http header 请求头触发的缓存策略来做缓存,包含强缓存和协商缓存。

  • 硬盘中的缓存:对比 Memory Cache 读取速度慢,但是容量大、缓存时效长
  • 它根据 HTTP Header 中的字段判断哪些资源需要被缓存、哪些资源可以不请求直接使用、哪些资源已经过期需要重新请求。即使在跨站点的情况下相同地址的资源一旦被硬盘缓存下来就不会再次去请求数据
  • 对于大文件来说大概率在硬盘中缓存,反之内存缓存优先;当前系统内存使用率高的情况下文件优先存储进硬盘

Push Cache

当以上三种缓存都没有命中时才会使用Push Cache。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂。这种缓存一般用不到。

我们通过控制台network,最直观的查看资源用的缓存方式。如图所示:

缓存过程

meta标签设置http-equiv

http-equiv属性可以被称作http响应头,可对整个页面进行缓存设置。

注意:设置meta标签只缓存页面内容,不会缓存页面引用的资源文件。

<!--设定网页缓存时效-->
<meta http-equiv="Cache-Control" content="max-age=7200" />
<!--设定网页的到期时间-->
<meta http-equiv="Expires" content="Mon, 20 Jul 2009 23:00:00 GMT" />

用法:一般用于静态HTML页面缓存。

缺点:浏览器支持情况不同。expires支持较好。Cache-Control不一定管用。

强缓存和协商缓存

浏览器的缓存分为强缓存协商缓存,当客户端请求某个资源的时候,获取缓存的流程如下:

  1. 浏览器第一次打开一个网页获取资源后,根据返回的header(响应头)信息来告诉如何缓存资源。响应头携带(Last-Modified)内容最后修改时间。
  2. 下次请求,先根据这个资源的http header(响应头)判断它是否命中强缓存cache-controlexpires信息),如果命中,则直接从本地缓存中获取资源(包括缓存header信息),未命中则向服务器请求资源。
  3. 当强缓存没有命中时,客户端会发送请求到服务器,服务器通过第一次请求返回的请求头字段信息If-Modified-SinceEtag/If-None-Match)验证这个资源是否命中协商缓存,这个过程成为http再验证,如果命中,服务器直接返回请求(返回新的响应头信息更新缓存中的对应header信息)而不返回资源,告诉客户端从缓存中获取,客户端收到返回后就直接从客户端缓存获取资源。协商缓存返回的状态码一般为304。
  4. 强缓存和协商缓存的共同之处在于:如果命中缓存,服务器不会返回资源;区别是:强缓存不发送请求到服务器(不与服务器通信),但是协商缓存会发送请求到服务器
  5. 当协商缓存没有命中时,服务器会返回资源给客户端。
  6. 当ctrl+F5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存
  7. 当F5刷新页面时,跳过强缓存但会检查协商缓存。

浏览器第一次请求

浏览器后续请求

强制刷新ctrl + f5 ,请求头header带有Cache-control:no-cache(为了兼容,还带了 Pragma: no-cache),同时不带有if-not-match / If-Modified-Since,所以请求服务器协商缓存会被当做失效,返回200和最新内容。

强缓存相关header字段

强缓存可以通过设置两种响应头实现:Expires 和 Cache-Control。

  1. Expires策略:数据缓存到期时间,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。Expires设置失效时间,精确到时分秒。不过Expires 是HTTP 1.0的东西,现在浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
  2. Cache-control策略(重点):Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。同时设置的话,其优先级高于Expires。可以指定一个 max-age 字段,表示缓存的内容将在一定时间后失效。比如:Cache-Control:max-age=300 时,则代表在这个请求正确返回的5分钟内再次加载资源,就会命中强缓存。

http协议头Cache-Control

值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age,各个消息中的指令含义如下:

  1. Public指示响应可被任何缓存区缓存。
  2. Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当前用户的部分响应消息,此响应消息对于其他用户的请求无效。
  3. no-cache指示请求或响应消息不能缓存
  4. no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
  5. max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
  6. min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
  7. max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

协商缓存相关的header字段

协商缓存可以通过设置两种响应头实现:Last-Modified 和 ETag 。

Last-Modifued/If-Modified-Since和Etag/If-None-Match这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modifued或者Etag),则后续请求会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modifued或者Etag字段,则请求头也不会有对应字段。

Last-Modified/If-Modified-Since要配合Cache-Control使用。

  1. Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
  2. If-Modified-Since:当资源过期时(浏览器判断Cache-Control标识的max-age过期),发现响应头具有Last-Modified声明,则再次像服务器请求时带上头if-modified-since,表示请求时间。服务器收到请求后发现有if-modified-since则与被请求资源的最后修改时间进行对比(Last-Modified),若最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;若最后修改时间较旧(小),说明资源无新修改,响应HTTP 304 走缓存。

Etag/If-None-Match也要配合Cache-Control使用

  1. Etag:服务器响应时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
  2. If-None-Match:当资源过期时,浏览器发现响应头里有Etag,则再次像服务器请求时带上请求头if-none-match(值是Etag的值)。服务器收到请求进行比对,决定返回200或304
    为什么既有Last-Modified还有Etag(两者为什么并存,有什么好处)

使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;
  2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);
  3. 某些服务器不能精确的得到文件的最后修改时间。

这时,利用Etag能够更加准确的控制缓存,因为Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符。Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

协商缓存生效,返回304和Not Modified:

协商缓存失效,返回200和请求结果:

用户的行为对缓存的影响

强缓存

  • 不会向服务器发送请求,直接从缓存中读取资源,可以设置两种 HTTP Header 来实现:Expires、Cache-Control

Expires

  • 缓存过期时间用来指定资源的过期时间,是服务器端的具体的时间点,结合 last-modified 来使用
  • 是 HTTP/1 的产物,受限于本地时间,如果本地时间修改可能会造成缓存失效

Cache-Control

  • 可以在请求头或响应头中来设置,多个指令配合使用达到多个目的
  • 是 HTTP/1.1 的产物,如果和 Expires同时存在,那么它的优先级要高,所以 Expires 的存在成为了一种兼容性的写法

协商缓存

  • 强缓存的依据来自于缓存是否过期,而不关心服务端文件是否已经更新,这可能会导致加载的文件不是服务端最新的内容,此时我们就需要用到协商缓存
  • 协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识决定是否使用缓存的过程,主要分两种情况
    • 协商缓存生效返回 304 和 Not Modified
    • 协商缓存失效返回 200 和请求的结果
  • 协商缓存可以通过设置两种 HTTP Header 来实现:Last-Modified 和 ETag

Last-Modified

  • 浏览器在第一次返回资源时,在响应头中添加 Last-Modified 的 header,值是这个资源在服务器上的最后的修改时间浏览器接收后缓存文件和 header
  • 浏览器下一次请求这个资源,浏览器检测到有 Last-Modified 这个 header,于是添加 If-Modified-Since 这个 header,值就是 Last-Modified 中的值;服务器再次收到这个资源请求,会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化,返回 304 和空的响应体,直接从缓存读取,如果 If-Modified-Since 的时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和 200
  • Last-Modified 的弊端:
    • 如果本地打开缓存文件,即使没有对文件进行修改,但还是会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源
    • 因为 Last-Modified 只能以秒计时,如果在不可感知的时间内修改完成文件,那么服务端会认为资源还是命中了,不会返回正确的资源

既然根据文件修改时间来决定是否缓存尚有不足,能否可以直接根据文件内容是否修改来决定缓存策略?所以在 HTTP / 1.1 出现了 ETag 和If-None-Match

ETag

  • ETag 是服务器响应请求时,返回当前资源文件的一个唯一标识,只要资源有变化 ETag 就会重新生成
  • 浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的 Etag 值放到 request header 里的 If-None-Match 里,服务器只需要比较客户端传来的 If-None-Match 跟自己服务器上该资源的 ETag 是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器发现 ETag 匹配不上,那么直接以常规 GET 200 回包形式将新的资源(当然也包括了新的 ETag)发给客户端;如果 ETag 是一致的,则直接返回 304 知会客户端直接使用本地缓存即可。
  • Last-Modified 和 ETag 的区别:
    • 精度上 ETag 优于 Last-Modified
    • 性能上 ETag 逊于 Last-Modified
    • 优先级上服务器优先考虑 ETag

缓存机制

  • 强制缓存优先于协商缓存进行,若强制缓存生效则直接使用缓存,若不生效则进行协商缓存,协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回 200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回 304,继续使用缓存。
  • 如果什么缓存策略都没设置,那么浏览器会怎么处理?对于这种情况,浏览器会采用一个启发式的算法,通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间。
  • 浏览器缓存分为强缓存和协商缓存,两者有两个比较明显的区别:
    • 如果浏览器命中强缓存,则不需要给服务器发请求;而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
      在 chrome 中强缓存(虽然没有发出真实的 http 请求)的请求状态码返回是 200 (from cache);
    • 而协商缓存如果命中走缓存的话,请求的状态码是 304 (not modified)。 不同浏览器的策略不同,在 Fire Fox中,from cache 状态码是 304.

实际应用场景

  • 频繁变动的资源:Cache-Control: no-cache
  • 不常变化的资源:Cache-Control: max-age=31536000,一年的有效期,比如 jQuery 类库基本不换化

用户行为对浏览器缓存的影响

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

1.http和https的基本概念

http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

https: 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。https协议的主要作用是:建立一个信息安全通道,来确保数据的传输,确保网站的真实性。(简单来说https协议是由http和ssl协议构建的可进行加密传输和身份认证的网络协议,比http协议的安全性更高。)https的SSL加密是在传输层实现的。

2.http和https的区别?

  1. Https协议需要ca证书,费用较高。
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  3. 使用不同的链接方式,端口也不同,一般而言,http协议的端口为80,https的端口为443
  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

3.https协议的工作原理

客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤:

  1. 客户使用https url访问服务器,则要求web 服务器建立ssl链接。
  2. web服务器接收到客户端的请求之后,会将网站的证书(证书中包含了公钥),返回或者说传输给客户端。
  3. 客户端和web服务器端开始协商SSL链接的安全等级,也就是加密等级。
  4. 客户端浏览器通过双方协商一致的安全等级,建立会话密钥,然后通过网站的公钥来加密会话密钥,并传送给服务端。
  5. web服务器通过自己的私钥解密出会话密钥。
  6. web服务器通过会话密钥加密与客户端之间的通信。

4.https协议的优点

  1. 使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
  2. HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
  3. HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
  4. 谷歌搜索算法,采用HTTPS加密的网站在搜索结果中的排名将会更高。

5.https协议的缺点

  1. https握手阶段比较费时,会使页面加载时间延长50%,增加10%~20%的耗电。
  2. https缓存不如http高效,会增加数据开销。
  3. SSL证书也需要购买,功能越强大的证书费用越高。比如使用泛域名SSL证书。
  4. SSL证书需要绑定IP,不能再同一个ip上绑定多个域名,ipv4资源支持不了这种消耗。

6.tcp三次握手,一句话概括

客户端和服务端都需要知道各自是否可以进行收发,因此需要三次握手。相当于敲门,用于确认是否可以开始发送。

三次握手可以简化为:C发起请求连接,S确认,S也发起连接,C确认。我们再看看每次握手的作用:第一次握手:S只可以确认自己可以接受C发送的报文段;第二次握手:C可以确认S收到了自己发送的报文段;并且可以确认自己可以接受S发送的报文段;第三次握手:S可以确认C收到了自己发送的报文段。

7.说一下http2.0

简要概括:http2.0是基于1999年发布的http1.0之后的首次更新。

提升访问速度:请求资源所需时间更少,访问速度更快,相比http1.0。

多路复用:多路复用允许同时通过一个TCP连接发送多个请求。改善了:在http1.1中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制(连接数量),超过限制会被阻塞。

头部压缩:相同请求不需要再次发送请求头等信息,通信期间几乎不会改变的请求头的通用的键值,如user-Agent和content-Type只发送一次,相当于做了一层缓存

二进制分帧:HTTP2.0会将所有的传输信息分割为更小的信息或者帧,并对他们进行二进制编码。

8.400和401、403状态码

(1)400状态码:请求无效

产生原因:

前端提交数据的字段名称和字段类型与后台的实体没有保持一致

前端提交到后台的数据应该是json字符串类型,但是前端没有将对象JSON.stringify转化成字符串。

解决方法:

对照字段的名称,保持一致性

将obj对象通过JSON.stringify实现序列化

(2)401状态码:当前请求需要用户验证

(3)403状态码:服务器已经得到请求,但是拒绝执行

9.HTTP支持哪些请求方式

get、post、head、options、put、delete、trace、connect

10.HTTP请求的options,head方式

head:类似于get请求,只不过返回的响应中没有具体的内容,用户获取报头

options:允许客户端查看服务器的性能,比如说服务器支持的请求方式等等。

11.GET和POST的区别

  1. 副作用指对服务器上的资源做改变,比如搜索是无副作用的,注册是副作用的。Get 多用于无副作用场景,Post 多用于副作用场景。
  2. get参数通过url传递,post放在request body(请求体)中。
  3. get请求连接长度是有限制的(浏览器或服务器限制,HTTP不限制),post没有。
  4. post比get更加安全。因为get参数直接暴露在url中,不能用来传递敏感信息。
  5. get只能进行url编码。而post可以通过 request body来传输比 Get 更多的数据,支持多种编码方式且不对数据类型限制,如application/x-www-form-urlencodedmultipart/form-dataapplication/jsontext/xml
  6. get参数会被浏览器主动缓存,保留在浏览器历史记录中,而post参数不会
  7. get和post本质都是tcp连接,但由于浏览器和服务器的限制导致传输有一些差异。
  8. get产生一个tcp数据包,post产生两个tcp数据包。get方式会把请求头和data数据一并发出,服务器响应200;post请求先发请求头,服务器响应100,再发请求体数据,服务器响应200。

12.浏览器缓存机制

详见:浏览器的缓存机制详解

13.前端http优化

  1. 减少http请求数(http/1):合并css,合并JS,合并图片。但这种优化方式在http2.0中无效。
  2. 减少DNS查询时间
  3. 使用CDN
  4. 利用浏览器缓存:传输轻量、细粒度的资源,以便独立缓存和并行传输。因为HTTP/2的多路复用和头部压缩特性。
  5. 最小化HTTP请求大小
  6. 最小化HTTP响应大小
  7. 减少不必要的重定向
  8. 服务端渲染:允许服务端主动发送额外的资源。类似于ssr首屏的处理。

http2.x多路复用

多路复用使得不同的请求共用一个TCP连接,允许多个资源并行下载,避免建立多个连接带来不必要的额外开销。它消除了HTTP/1.1中的线头阻塞问题。头部压缩进一步减少了多个HTTP请求的开销,因为每个请求开销都小于未压缩的等价HTTP/1.1请求。

PS:文件合并依然可以提高压缩率,但它带来了代价高昂的缓存失效。即使有一行CSS改变了,浏览器也会强制重新加载你 所有的 CSS声明。另外,不是所有页面都使用了合并后的CSS或JavaScript文件中的全部声明或函数。

14.列举HTTP状态码,及如何获取

在原生xhr请求完成可通过XMLHttpRequest的实例中的status属性来获取。

var xhr = new XMLHttpRequest()
// open方法的第三个参数是是否异步
xhr.open('GET', 'http://xxxx.com/api?a=1&b=2' ,true)
xhr.send(null)
xhr.onreadystatechange = () =>{
	if(xhr.readyState==4){
		console.log(xhr.status, xhr.responseText)
	}
}
  • 100,接受的请求正在处理,信息类状态码
  • 2xx(成功)表示成功处理了请求的状态码
  • 200(成功)服务器已成功处理了请求
  • 206,服务器成功处理了部分请求,比如做分段下载(head方法获取文件大小,请求头字段用Range)
  • 3xx(重定向)表示要完成请求,需要进一步操作。通常这些状态代码用来重定向。
  • 301,永久性重定向,表示资源已被分配了新的 URL
  • 302,临时性重定向,表示资源临时被分配了新的 URL
  • 303,表示资源存在另一个URL,用GET方法获取资源
  • 304,(未修改),http请求的缓存问题引起,服务端不会返回新内容
  • 307,临时重定向
  • 4xx,(请求错误)这些状态码表示请求可能出错,妨碍了服务器的处理
  • 400,(错误请求)服务器不理解请求的语法
  • 401,当前请求需要用户验证
  • 403,(禁止)服务器拒绝请求(服务器已经得到请求,但是拒绝执行)
  • 404,(未找到)服务器找不到请求网页
  • 5xx,(服务器错误)这些状态码表示服务器在尝试处理请求时发生内部错误。
  • 500,(服务器内部错误)服务器遇到错误,无法完成请求
  • 502,服务端负载比较高,导致连接超时
  • 503,表示服务器宕机,无法处理请求

15.TCP和UDP的区别(了解)

UDP:

  • 面向无连接,不需要三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。
  • 支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。
  • 面向报文
  • 不可靠性:通信都不需要建立连接,想发就发,也不会关心对方是否已经正确接收到数据了,这样的情况肯定不可靠。
  • 恒定速率:UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。
  • 头部开销小,传输数据报文时是很高效的。
  • 没有缓存,不会备份数据。

TCP:

  • 面向连接的、可靠的、基于字节流的传输层通信协议。流就是指不间断的数据结构。
  • 三次握手:相当于敲门,告知和确认可以开始收发。防止出现失效的连接请求,从而产生错误。这样能建立可靠的连接。建立连接,是为数据的可靠传输打下了基础。
  • 只能进行点对点的数据传输,不支持多播和广播传输方式。
  • 每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收
  • 拥塞控制:当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞
  • 全双工通信:TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段
  • TCP 针对数据包丢失的情况,可以采用重传机制解决

16.Chrome浏览器HTTP最大请求并发数限制

同一域名下,同一GET请求的并发数是1,也就是说上一个请求结束,才会执行下一个请求,否则置入队列等待发送;

同一域名下,不同GET/POST请求的并发数量是6。当发送的请求数量达到6个,并且都没有得到响应时,后面的请求会置入队列等待发送。

历史悠久的超文本传输协议,即HTTP标准。HTTP/2在2015年5月被批准,目前浏览器已经支持HTTP/2。

HTTP/2构建在Google SPDY协议基础之上。NGINX是最早支持SPDY的,也同样率先支持了HTTP/2。NGINX还发布了详尽的白皮书(PDF),介绍了HTTP/2以及它如何基于SPDY构建,并展示了如何实现这个新协议。

SPDY是HTTP/2的上一代,总体性能相同。因为它已经出现好多年了,所以先前有很多浏览器支持SPDY不支持HTTP/2。不过,现在浏览器都开始支持HTTP/2。

HTTP/2的重要特性完全源自SPDY。

  • HTTP/2是二进制(而文本)协议,因此更简洁高效;
  • 它针对每个域只使用一个多路复用的连接,而不是每个文件一个连接;
  • 首部使用特制的HPACK协议(而非SPDY中使用的gzip)压缩;
  • HTTP/2设计了复杂的优先级排定规则,帮助浏览器首先请求最急需的文件,而NGINX已经支持(SPDY的方案要简单一些)。

注意:严格来讲,SPDY和HTTP/2都不需要TLS,但它们在使用SSL/TLS的时候用处最大,而且浏览器只在使用SSL/TLS时才支持SPDY或HTTP/2。

现在是否需要迁移到HTTP/2

HTTP/2并不是万能的,它只对某些Web应用有用,对另外一些则没那么有用。

如果你使用SSL/TLS(以后简称TLS),那么HTTP/2可以提升网站性能。如果你没有,那在使用HTTP/2之前要先支持TLS。这时候,使用TLS的性能损耗大致可以被使用HTTP/2的性能提升抵销。

HTTP2与HTTP1.1最重要的区别就是解决了线头阻塞的问题!其中最重要的改动是:多路复用 (Multiplexing)。

如何升级:要求nginx的最低版本是1.10.0,openssl的最低版本是1.0.2,http/2在浏览器实现上基本只支持https,也就是说当前所有实现 HTTP/2的 Web 浏览器都只支持加密。。

HTTP/2有五大优势

  1. 每个服务器只用一个连接。HTTP/2对每个服务器只使用一个连接,而不是每个文件一个连接。这样,就省掉了多次建立连接的时间,这个时间对TLS尤其明显,因为TLS连接费时间。
  2. 加速TLS交付。HTTP/2只需一次耗时的TLS握手,并且通过一个连接上的多路利用实现最佳性能。HTTP/2还会压缩首部数据,省掉HTTP/1.x时代所需的一些优化工作,比如拼接文件,从而提高缓存利用率。
  3. 简化Web应用。使用HTTP/2可以让Web开发者省很多事,因为不用再做那些针对HTTP/1.x的优化工作了。
  4. 适合内容混杂的页面。HTTP/2特别适合混合了HTML、CSS、JavaScript、图片和有限多媒体的传统页面。浏览器可以优先安排那些重要的文件请求,让页面的关键部分先出现,快出现。
  5. 更安全。通过减少TLS的性能损失,可以让更多应用使用TLS,从而让用户信息更安全。

HTTP/2的多路复用示意图

HTTP/2不足

  1. 单连接开销比较大。HPACK数据压缩算法会更新两端的查找表。这样可以让连接有状态,而破坏状态就意味着要重建查找表,另外单连接占用内存较多。
  2. 你可能不需要SSL。如果你的数据不需要保护,或者已经使用DRM或其他编码进行保护了,那么TLS的安全性对你可能无所谓。
  3. 需要抛弃针对HTTP/1.x的优化。HTTP/1.x优化在支持HTTP/2的浏览器中会影响性能,因此可能需要花时间把它们推倒重来。
  4. 对下载大文件不利。如果你的应用主要提供大文件下载或者流媒体播放,那可能不想用TLS,而且在只有一个流的情况下,多路复用也体现不出什么优势。
  5. 你的客户也许不在乎。你的客户很可能不在乎他分享的自家猫咪的视频是否受到TLS和HTTP/2的保护。

总之,一切要看性能。这方面,有好消息也有坏消息。

好消息是我们在内部对NGINX做过测试,结果从理论上能够得到印证:对于要通过典型网络延迟请求的混合内容网页,HTTP/2的性能好于HTTP/1.x和HTTPS。基于连接的RTT(延迟),结果可以分三种情况。

  • 很低的RTT(0-20ms):HTTP/1.x、HTTP/2和HTTPS基本无差别。
  • 典型网络RTT(30-250ms):HTTP/2比HTTP/1.x快,而且它们都比HTTPS快。美国两个相邻城市间的RTT约为30 ms,而东西海岸间(约3000英里)则约为70 ms。东京到伦敦间最短路径的RTT大约240 ms。
  • 高RTT(300ms及以上):HTTP/1.x比HTTP/2快,后者又比HTTPS快。

终止HTTP/2和TLS(已有环境不必改动)

终止协议意味着客户端使用期望的协议连接代理服务器,比如TLS或HTTP/2,然后代理服务器再去连接应用服务器、数据库服务器等,但不需要使用相同的协议,如下图所示。

使用独立的服务器终止协议意味着使用多服务器架构。多服务器可能是多个物理服务器、多个虚拟服务器,或者AWS这样的云环境中的多个虚拟服务器实例。多服务器就比单服务器复杂,或者比应用服务器/数据库服务器的组合复杂。不过,多服务器架构有很多好处,而且很多流量大的网站也必须用这种架构。

配置了服务器或者虚拟服务器之后,很多事情都成为可能。新服务器可以分担其他服务器的负载,可用于负载平衡、静态文件缓存和其他用途。另外,也可以让添加和替换应用服务器或其他服务器更容易。

NGINX和NGINX Plus经常被用来终止TLS和HTTP/2协议、负载平衡。已有环境不必改动,除非要把NGINX服务器挪到前端。

找出为HTTP/1.x优化的代码

在决定采用HTTP/2之前,首先得知道你的代码有哪些是针对HTTP/1.x优化过的。大概有四方面的优化。

  1. 分域存储。为了实现并行请求文件,你可能把文件分散到了不同的域里,CDN会自动这么做。但分域存储会影响HTTP/2的性能,建议使用HTTP/2友好的分域存储(建议七),只针对HTTP/1.x用户分域。
  2. 雪碧图。雪碧图把很多图片拼成一个文件,然后通过代码按需取得每个图片。雪碧图在HTTP/2的环境下没太大用处,但还是有点用的。
  3. 拼接的代码文件。与使用雪碧图的原因类似,很多独立的文件也会被弄成一个,然后浏览器再从其中找到并运行需要的文件。
  4. 插入行内的文件。CSS代码、JavaScript代码,甚至图片等被直接插到HTML文件中的内容。这样可以减少文件传输,代价是初始HTML文件较大。

后面三种优化都涉及把小文件塞进一个较大的文件里,目的是减少新建连接的初始化和握手,这些操作对TLS而言非常费时间。

第一种优化即分域存储恰恰相反,强制打开多个连接,目的是并行地从不同的域获取文件。这两种看似矛盾的技术对于HTTP/1.x下的站点却十分有效。然而,要用好这两种技术,必须投入大量时间、精力和资源,用于实现、管理和运维。

在采用HTTP/2之前,需要找出应用了这些优化的代码,分析一下它们会不会影响你的应用设计和工作流程。这样在迁移到HTTP/2之后,就可以着手改造它们,甚至撤销某些优化。

部署HTTP/2

事实上,部署HTTP/2或SPDY并不难。如果你使用NGINX,只要在配置文件中启动相应的协议就可以了,参见这里了解如何启用HTTP/2(PDF)。浏览器和服务器会协商采用什么协议,如果浏览器支持HTTP/2(而且也在使用TLS),就会使用HTTP/2。

配置完服务器后,使用支持HTTP/2浏览器的用户就会基于HTTP/2运行你的应用,而使用旧版本浏览器的用户则会继续使用HTTP/1.x运行你的应用,如下图所示。如果你的网站流量非常大,那么应该监测改变前后的性能,对于性能降低的情况,可能就得撤销更改。

注意:使用HTTP/2及其单连接之后,NGINX某些配置的重要性会很明显,特别要注意的是output_buffersproxy_buffersssl_buffer_size等指令,多测试一下。参见general configuration notes,特定的SSL建议(在这里 and here),以及NGINX关于SSL性能的白皮书(PDF)。

注意:使用HTTP/2传输密文要格外注意。HTTP/2的RFC中有一个长长的列表,列出了要避免的加密套件。

再谈HTTP/1.x优化

撤销和修改针对HTTP/1.x优化的代码居然是实现HTTP/2最有创意的部分。这里面有几个问题要注意。

在开始运作之前,必须考虑旧版本浏览器用户是否好过。之后,可以采取三个策略撤销和修改HTTP/1.x的优化。

  • 什么也不用做。假如你并没有针对HTTP/1.x做过优化,或者只做过少量优化,那么你几乎什么也不用做,就可以直接迁移到HTTP/2。
  • 有选择地去做。第二种情况是减少合并某些文件,而不是完全不合并。比如,牵扯到很多场景的雪碧图就不用动,而被塞得满满的HTML可能就要分离出来一些。
  • 完全撤销HTTP/1.x优化

缓存还是普适的。理论上,缓存操作非常适合小文件特别多的情况。但是,小文件多也意味着文件I/O多。因此一些相近文件的合并还是必要的,一方面要考虑工作流程,另一方面要考虑应用性能。建议多关注一下其他人在过渡到HTTP/2过程中的一些经验。

实现智能分域

分域存储可能是最极端但也最成功的HTTP/1.x优化策略。它能够提升HTTP/1.x下的应用性能,但在HTTP/2之下,其性能提升可以忽略不讲(因为只有一个连接。)

对HTTP/2友好的分域,要保证以下两点。

  • 让多个域名解析到同一个IP。
  • 确保证书包含通配符,以便所有分域名都可以使用,适当的多域证书当然也可以。

具体细节,请参考这里

有了这些保障,分域还会继续对HTTP/1.x有效,即域名仍然可以触发浏览器创建更多连接,但对HTTP/2则无效,因为这些域名会被看成同一个域,一个连接就可以访问所有域名了。

小结

HTTP/2和TLS组合可以提升你的站点性能,并且让用户觉得你的网站很安全。