性能优化(1)-请求响应优化

一、请求和响应优化

目的:更快的内容到达时间。

1.减少DNS查找:每次主机名的解析都需要一次网络往返,从而增加了请求的延迟时间,同时还会阻塞后续的请求。

  • 重用 TCP 连接:尽可能的使用持久连接,以消除因 TCP 握手和慢启动导致的延迟。
    3.减少HTTP重定向: HTTP冲定向需要额外的DNS查询、TCP握手等非常耗时,最佳的重定向次数为0.
  • 压缩传输的资源:比如 Gzip、图片压缩。
  • 使用缓存:比如 HTTP 缓存、CDN 缓存、Service Worker 缓存。
  • 使用 CDN(内容分发网络):把数据放在离用户地理位置更近的地方,可以明显减少每次 TCP 连接的网络延迟,增大吞吐量。
  • 删除没有必要请求的资源。
    8,在客户端缓存资源:缓存必要的应用资源,避免每次都重复请求相同的内容,例如多图片下载可以考虑使用缓存
    9,内容在传输前先压缩:传输数据之前应该先压缩应用资源,把要传输的字节减少到最小,在压缩的时候确保对每种不同的资源采用最好的压缩手段。
    10,消除不必要的请求开销:减少请求的HTTP首部数据(比如HTTP COokie)
    11,并行处理请求和响应:请求和响应的排队都会导致延迟,可以尝试并行的处理请求和响应(利用多个HTTP1.1连接实现并行下载,在可能的情况下使用HTTP管道计数)
    12.针对协议版本采取优化措施。升级到 HTTP2.0。
  • 根据需要采用服务端渲染方式。这种方式可以解决 SPA 应用首屏渲染慢的问题。
    14,采用预渲染的方式快速加载静态页面。页面渲染的极致性能,比较适合静态页面。

二、DNS解析

当浏览器从(第三方)服务器请求资源时,必须先将该跨域域名解析为IP 地址,然后浏览器才能发出请求。此过程称为DNS解析。DNS 作为互联网的基础协议,其解析的速度似乎很容易被网站优化人员忽视。现在大多数新浏览器已经针对DNS解析进行了优化,比如DNS缓存。典型的一次 DNS 解析需要耗费 20-120 毫秒,所花费的时间几乎可以忽略不计,但是当网站中使用的资源依赖于多个不同的域的时候,时间就会成倍的增加,从而增加了网站的加载时间。比如在某些图片较多的页面中,在发起图片加载请求之前预先把域名解析好将会有至少5%的图片加载速度提升。

一般来说,在前端优化中与 DNS 有关的有两点:

  • 减少 DNS 的请求次数
  • 进行DNS预获取: DNS Prefetch

减少DNS查找

域名系统(DNS)将主机名映射到IP地址,就像电话簿将人们的姓名映射到他们的电话号码一样。在浏览器中输入www.taobao.com时,浏览器联系的DNS解析器将返回该服务器的IP地址。DNS有成本。DNS通常需要20-120毫秒来查找给定主机名的IP地址。在DNS查找完成之前,1浏览器无法从该主机名下载任何内容。

缓存DNS查找以提高性能。这种缓存可以在由用户的ISP或局域网维护的特殊缓存服务器上进行,但是在个别用户的计算机上也会发生缓存。

DNS信息保留在操作系统的DNS缓存中(Microsoft Windows上的“DNS客户端服务”) 。大多数浏览器都有自己的缓存,与操作系统的缓存分开。只要浏览器将 DNS 记录保留在其自己的缓存中,它就不会对操作系统发出记录请求进行打扰。
默认情况下, Internet Explorer会缓存30分钟的DNS查找,这是由DnsCacheTimeout注册表设置指定的。 Firefox在network.dnsCa lcheExpiration 配置设置的控制下缓存 DNS 查找1分钟。Chrome 也是1分钟。

当客户端的DNS缓存为空(对于浏览器和操作系统)时, DNS查找的次数等于网页中唯一主机名的数目。这包括在页面的URL,图像,脚本文件,样式表,Flash 对象等中使用的主机名。减少唯一主机名的数量将减少 DNS 查找的数量。

减少域名的数量有可能减少页面中并行下载的数量。避免DNS查找会减少响应时间,但是减少并行下载可能会增加响应时间。我的指导原则是将这些资源划分为至少两个但不超过四个域名。这将在减少 DNS 查找和允许高度并行下载之间取得良好的折衷。

dns-prefetch

DNS-prefetch (DNS预获取)是尝试在请求资源之前解析域名。这可能是后面要加载的文件,也可能是用户尝试打开的链接目标。域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验。
dns-prefetch可帮助开发人员掩盖DNS解析延迟。HTML 元素通过dns-prefetch的rel属性值提供此功能。然后在hrlef 属性中指要跨域的域名:

<link rel="dns-prefetch" href="https://fonts.googleapis.com/">

比如这是淘宝网对 dns-prefetch 的使用:
在这里插入图片描述

扫描二维码关注公众号,回复: 14876966 查看本文章

还可以通过使用 HTTP Link 字段将 dns-prefetch (以及其他资源提示)指定为 HTTP 标头:

Link: <https://fonts.gstatic.com/>; rel=dns-prefetch

每当站点引用跨域域上的资源时,都应在 元素中放置 dns-prefetch 提示,但是要记住一些注意事项。
(1) dns-prefetch仅对跨域域上的DNS查找有效,因此请避免使用它来指向您的站点或域。这是因为,到浏览器看到提示时,您站点域背后的IP已经被解析。
(2) dns-prefetch需慎用,多页面重复DNS预解析会增加重复DNS查询次数。
(3)默认情况下浏览器会对页面中和当前域名(正在浏览网页的域名)不在同一个域的域名进行预获取,并且缓存结果,这就是隐式的DNSPrefetch。如果想对页面中没有出现的域进行预获取,那么就要使用显示DNS Prefetch了。
(4)虽然使用 DNS Prefetch能够加快页面的解析速度,但是也不能滥用,因为有开发者指出禁用 DNS预读取能节省每月100亿的DNS 查询。


<meta http-equiv="x-dns-prefetch-control" content="off">

更多DNS解析优化

  1. 延长 DNS 缓存时间
  2. 尽可能使用 A或AAAA 记录代替 CNAME
  3. 使用 CDN 加速域名
  4. 自己搭建 DNS 服务

附:清除 DNS 缓存

1、清除浏览器 DNS 缓存
清除 DNS 缓存: chrome://net-internals/#dns
有时候也需要同时清除套接字缓存池: chrome://net-internals/#sockets
2、清除系统 DNS 缓存

#在Windows中查看DNS缓存记录
ipconfig /displaydns

#在Windows中清除DNS缓存记录
ipconfig /flushdns

#在macOS中清除DNS缓存记录
sudo killall -HUP mDNSResponder

三、HTTP 长连接

短连接

HTTP 协议的初始版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。
在这里插入图片描述
以早期的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大问题。但是随着 HTTP 的大量普及,文档中包含大量富文本(图片、视频等资源)的情况多了起来。

比如,使用浏览器浏览一个包含多张图片的 HTMl 页面时,在发送请求访问 HTMl 页面资源的同时,也会请求该 HTML 页面包含的其它资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信录的开销。
在这里插入图片描述
为了解决这个问题,有些浏览器在请求时,用了一个非标准的 Connection 字段。

Connection: keep-alive

这个字段要求服务器不要关闭 TCP 连接,以便其他请求复用。服务器同样回应这个字段。

Connection: keep-alive

一个可以复用的 TCP 连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。

长连接

1997 年 1 月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,直到现在还是最流行的版本。

HTTP 1.1 版的最大变化,就是引入了持久连接(HTTP Persistent Connections),即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive。

在这里插入图片描述
持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外,减少开销的那部分时间,使 HTTP 请求和响应能够更早的结束,这样 Web 页面的显示速度也就相应提高了。

客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送 Connection: close,明确要求服务器关闭 TCP 连接。

目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。

管道机制

HTTP 1.1 版还引入了管道机制(pipelining),即在同一个 TCP 连接里面,客户端可以同时发送多个请求。这样就进一步改进了 HTTP 协议的效率。

从前发送请求后需等待并接收响应,才能发送下一个请求。管线化技术出现后,不用等待响应即可直接发送下一个请求。这样就能够做到同时并行发送多个请求,而不需要一个接一个的等待响应了,与挨个连接相比,用持久连接可以让请求更快结束。而管线化技术则比持久连接还要快。请求数越多,时间差就越明显。

在这里插入图片描述
举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求,但是服务器还是按照顺序,先回应A请求,完成后再回应 B 请求。

Content-Length 字段

一个 TCP 连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是 Content-length 字段的作用,声明本次回应的数据长度。

Content-Length: 3495

上面代码告诉浏览器,本次回应的长度是3495个字节,后面的字节就属于下一个回应了。

在1.0版中,Content-Length 字段不是必需的,因为浏览器发现服务器关闭了 TCP 连接,就表明收到的数据包已经全了。

分块传输编码

使用 Content-Length 字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。

对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用“流模式”(stream)取代“缓存模式”(buffer)。
因此,1.1版规定可以不使用 Content-Length 字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有 Transfer-Encoding 字段,就表明回应将由数量未定的数据块组成。

Transfer-Encoding: chunked

每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。下面是一个例子。
在这里插入图片描述

长连接的缺点

虽然 HTTP 1.1 版允许复用 TCP 连接,但是同一个 TCP 连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。

为了避免这个问题,只有两种方法:

  • 一是减少请求数
  • 二是同时多开持久连接

这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入 CSS 代码、域名分片(domain sharding)等等。如果 HTTP 协议设计得更好一些,这些额外的工作是可以避免的。

四、HTTP2

2009 年,谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。
这个协议在 Chrome 浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。

2015年, HTTP/2发布。它不叫HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是HTTP/3

二进制协议

HTTP/1.1 版的头信息肯定是文本(ASCI编码) ,数据体可以是文本,也可以是二进制。HTTP/2则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。

多工

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

数据流

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

头信息压缩

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

服务器推送

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

五、压缩传输的数据资源

数据压缩是提高Web站点性能的一种重要手段。对于有些文件来说,高达70%的压缩比率可以大大减低对于带宽的需求。随着时间的推移,压缩算法的效率也越来越高,同时也有新的压缩算法被发明出来,应用在客户端与服务器端。

HTTP 响应数据压缩

压缩 JS、Css
这里所说的压缩指的是去除换行空格之类的压缩,文件内容不变。

使用 Gzip 压缩文本

浏览器和服务器之间会使用主动协商机制。浏览器发送 Accept-Encoding 首部,其中包含有它所支持的压缩算法,以及各自的优先级,服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding首部来告知浏览器它选择了哪一种算法。由于该内容协商过程是基于编码类型来选择资源的展现形式的,在响应中, Vary 首部中至少要包含Accept-Encoding ;这样的话,缓存服务器就可以对资源的不同展现形式进行缓存。
下面是一个请求响应的 HTTP 报文示例:
在这里插入图片描述

头部数据压缩

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

请求体数据压缩

前面我们介绍了HTTP协议中的Accept-Encoding/Content-Encoding机制。这套机制可以很好地用于文本类响应正文的压缩,可以大幅减少网络传输,从而一直被广泛使用。但HTTP请求的发起方(例如浏览器),无法事先知晓要访问的服务端是否支持解压,所以现阶段的浏览器没有压缩请求正文。
有一些通讯协议基于HTTP做了扩展,他们的客户端和服务端是专用的,可以放心大胆地压缩请求正文。例如WebDAV客户端就是这样。
实际的Web项目中,会存在请求正文非常大的场景,例如发表长篇博客,上报用于调试的网络数据等等。这些数据如果能在本地压缩后再提交,
就可以节省网络流量、减少传输时间。本文介绍如何对HTTP请求正文进行压缩,包含如何在服务端解压、如何在客户端压缩两个部分。
开始之前,先来介绍本文涉及的三种数据压缩格式:
DEFLATE,是一种使用 Lempel-Ziv 压缩算法(LZ77)和哈夫曼编码的压缩格式。详见 RFC 1951;
ZLIB,是一种使用 DEFLATE 的压缩格式,对应 HTTP 中的 Content-Encoding: deflate。详见 RFC 1950;
GZIP,也是一种使用 DEFLATE 的压缩格式,对应 HTTP 中的 Content-Encoding: gzip。详见 RFC 1952;

Content-Encoding 中的 deflate,实际上是 ZLIB。为了清晰,本文将 DEFLATE 称之为 RAW DEFLATE,ZLIB 和 GZIP 都是 RAW DEFLATE 的不同 Wrapper。

下面是一个简单示例。
(1)压缩请求正文数据

在这里插入图片描述
(2)在 Node 中解压请求正文中的数据
在这里插入图片描述
实际使用还需要匹配具体的服务器,比如 nginx、Apache 等。

六、强制缓存

对于强制缓存而言,如果浏览器判断所请求的目标资源有效命中,则可直接从强制缓存中返回请求响应,无须与服务器进行任何通信。

在介绍强制缓存命中判断之前,我们首先来看一段响应头的部分信息:
在这里插入图片描述
其中与强制缓存相关的两个字段是 expires 和 cache-control, expires 是在 HTTP 1.0 协议中声明的用来控制缓存失效日期时间戳的字段,它由服务器端指定后通过响应头告知浏览器,浏览器在接收到带有该字段的响应体后进行缓存。
若之后浏览器再次发起相同的资源请求,便会对比 expires 与本地当前的时间戳,如果当前请求的本地时间戳小于 expires 的值,则说明浏览器缓存的响应还未过期,可以直接使用而无须向服务器端再次发起请求。只有当本地时间戳大于 expires 值发生缓存过期时,才允许重新向服务器发起请求。
从上述强制缓存是否过期的判断机制中不难看出,这个方式存在一个很大的漏洞,即对本地时间戳过分依赖,如果客户端本地的时间与服务器端的时间不同步,或者对客户端时间进行主动修改,那么对于缓存过期的判断可能就无法和预期相符。
为了解决 expires判断的局限性,从HTTP 1.1 协议开始新增了 cache-control 字段来对 expires的功能进行扩展和完善。从上述代码中可见 cache-control设置了 maxage=31536000 的属性值来控制响应资源的有效期,它是一个以秒为单位的时间长度,表示该资源在被请求到后的 31536000 秒内有效,如此便可避免服务器端和客户端时间戳不同步而造成的问题。除此之外, cache-control 还可配置一些其他属性值来更准确地控制缓存,下面来具体介绍。

no-cache 和 no-store

设置no-cache并非像字面上的意思不使用缓存,其表示为强制进行协商缓存(后面会说) ,即对于每次发起的请求都不会再去判断强制缓存是否过期,而是直接与服务器协商来验证缓存的有效性,若缓存未过期,则会使用本地缓存。设置 no-store则表示禁止使用任何缓存策略,客户端的每次请求都需要服务器端给予全新的响应。 no-cache 和 no-store 是两个互斥的属性值,不能同时设置。
发送如下响应头可以关闭缓存。

Cache-Control: no-store

指定 no-cache或max-age=0表示客户端可以缓存资源,每次使用缓存资源前都必须重新验证其有效性。这意味着每次都会发起HTTP请求,但当缓存内容仍有效时可以跳过 HTTP 响应体的下载。

Cache-Control: max-age=0
Cache-Control: no-store

基于 ETag 的协商缓存

为了弥补通过时间戳判断的不足,从 HTTP 1.1 规范开始新增了一个 ETag 的头信息,即实体标签(Entity Tag)
其内容主要是服务器为不同资源进行哈希运算所生成的一个字符串,该字符串类似于文件指纹,只要文件内容编码存在差异,对应的 ETag 标签值就会不同,因此可以使用 ETag 对文件资源进行更精准的变化感知。下面我们来看一个使用 ETag进行协商缓存图片资源的示例,首次请求后的部分响应头关键信息如下,

代码示例

const http = require('http')
const fs = require('fs')
const url = require('url')
const etag = require('etag')

http.createServer((req, res) => {
    
    
  console.log(req.method, req.url)

  const {
    
     pathname } = url.parse(req.url)
  if (pathname === '/') {
    
    
    const data = fs.readFileSync('./index.html')
    res.end(data)
  } else if (pathname === '/img/01.jpg') {
    
    
    const data = fs.readFileSync('./img/01.jpg')
    res.writeHead(200, {
    
    
      Expires: new Date('2021-4-30 12:19:57').toUTCString()
    })
    res.end(data)
  } else if (pathname === '/img/02.jpg') {
    
    
    const data = fs.readFileSync('./img/02.jpg')
    res.writeHead(200, {
    
    
      'Cache-Control': 'max-age=5' // 滑动时间,单位是秒
    })
    res.end(data)
  } else if (pathname === '/img/03.jpg') {
    
     // 协商缓存
    const {
    
     mtime } = fs.statSync('./img/03.jpg')

    const ifModifiedSince = req.headers['if-modified-since']

    if (ifModifiedSince === mtime.toUTCString()) {
    
    
      // 缓存生效
      res.statusCode = 304
      res.end()
      return
    }

    const data = fs.readFileSync('./img/03.jpg')

    res.setHeader('last-modified', mtime.toUTCString())
    res.setHeader('Cache-Control', 'no-cache')
    res.end(data)
  } else if (pathname === '/img/04.jpg') {
    
     // 基于 ETag 的协商缓存
    const data = fs.readFileSync('./img/04.jpg')
    const etagContent = etag(data)

    const ifNoneMatch = req.headers['if-none-match']

    if (ifNoneMatch === etagContent) {
    
    
      res.statusCode = 304
      res.end()
      return
    }

    res.setHeader('etag', etagContent)
    res.setHeader('Cache-Control', 'no-cache')
    res.end(data)
  } else {
    
    
    res.statusCode = 404
    res.end()
  }
}).listen(3000, () => {
    
    
  console.log('http://localhost:3000')
})

缓存决策示例

该HTML文件中包含了一个JavaScript文件 script.js、一个样式表文件 style.css和一个图片文件 photo.jpg ,若要展示出该HTML中的内容就需要加载出其包含的所有外链文件。据此我们可针对它们进行如下设置。
首先 HTML 在这里属于包含其他文件的主文件,为保证当其内容发生修改时能及时更新,应当将其设置为协商缓存,即为 cache-control字段添加 no-cache属性值;其次是图片文件,因为网站对图片的修改基本都是更换修改,同时考虑到图片文件的数量及大小可能对客户端缓存空间造成不小的开销,所以可采用强制缓存且过期时间不宜过长,故可设置 cache-control 字段值为 max-age=86400 。
接下来需要考虑的是样式表文件 style.css ,由于其属于文本文件,可能存在内容的不定期修改,又想使用强制缓存来提高重用效率,故可以考虑在样式表文件的命名中增加文件指纹或版本号(比如添加文件指纹后的样式表文件名变为了 style.51ad84f7.css ),这样当发生文件修改后,不同的文件便会有不同的文件指纹,即需要请求的文件URL不同了,因此必然会发生对资源的重新请求。同时考虑到网络中浏览器与CDN 等中间代理的缓存,其过期时间可适当延长到一年,即 cache-control:max-age=31536000。
最后是 JavaScript脚本文件,其可类似于样式表文件的设置,采取文件指纹和较长的过期时间,如果JavaScript中包含了用户的私人信息而不想让中间代理缓存,则可为 cache-control 添加 private属性值。
从这个缓存策略的示例中我们可以看出,对不同资源进行组合使用强制缓存、协商缓存及文件指纹或版本号,可以做到一举多得:及时修改更新、较长缓存过期时间及控制所能进行缓存的位置。

七、CDN 缓存

CDN 全称 Content Delivery Network,即内容分发网络,它是构建在现有网络基础上的虚拟智能网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、调度及内容分发等功能模块,使用户在请求所需访问的内容时能够就近获取,以此来降低网络拥塞,提高资源对用户的响应速度。

回想在初学计算机网络的时候,常见的 B/S 模型都是浏览器直接向服务器请求所需的资源,但实际组网情况并非如此简单。因为通常对热门站点来说,同时发起资源请求的用户规模量往往非常巨大,而如果这些请求都发往同一服务器则极有可能造成访问拥塞。所以更合理的做法是将部分数据缓存在距离用户较近的边缘服务器上,这样不但可以提升对资源的请求获取速度,而且也能有效减少网站根节点的出口带宽压力,这便是 CDN 技术的基本思路。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从上述资源文件的请求域名中我们可以发现,这些文件都是从 CDN 网络上获取的,JavaScript 和样式表这样的文本文件与图片文件使用的是不同的 CDN 域名,而且 CDN 域名与主站域名也完全不同,这样的设计也是出于对性能的考虑。

猜你喜欢

转载自blog.csdn.net/woyebuzhidao321/article/details/129326871