Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

详解web缓存 #224

Open
wuxianqiang opened this issue Dec 31, 2019 · 0 comments
Open

详解web缓存 #224

wuxianqiang opened this issue Dec 31, 2019 · 0 comments

Comments

@wuxianqiang
Copy link
Owner

为什么要缓存

  1. 请求更快:通过将内容缓存在本地或距离最近的缓存服务器(CDN),大大加快网站加载速度。
  2. 节省带宽:对于已缓存的文件,可以减少请求带宽甚至无需请求网络。
  3. 降低服务器压力:在大量用户并发的情况下,服务器的性能受到限制,此时将一些静态资源放在网络的多个节点,可以起到负载均衡的作用,降低服务器压力。

缓存分类

  1. 服务端缓存(CDN)
  2. 客户端缓存(浏览器)

客户端浏览器的缓存类型

强缓存,返回状态码200,不会发送HTTP请求
协商缓存,返回状态码304,会发送HTTP请求

如何设置缓存

如何让浏览器缓存我们的静态资源,这也是一个需要由服务器与浏览器共同协作完成的事情。

  1. 协商缓存

在普通的GET请求报文中,附带If-Modified-Since字段,它将询问服务器端是否有更新的版本,本地文件的最后修改时间。如果服务器端没有新的版本,只需响应一个304状态码,客户端就使用本地版本。如果服务器端有新的版本,就将新的内容发送给客户端,客户端放弃本地版本。

服务端设置响应头

last-modified: Tue, 23 Apr 2019 10:09:21 GMT

客户端下次请求头会携带

if-modified-since: Tue, 23 Apr 2019 10:09:21 GMT

这里的条件请求采用时间戳的方式实现,但是时间戳有一些缺陷存在。文件的时间戳改动但内容并不一定改动。时间戳只能精确到秒级别,更新频繁的内容将无法生效。

为此HTTP1.1中引入了ETag来解决这个问题。ETag的全称是Entity Tag,由服务器端生成,服务器端可以决定它的生成规则。通常根据文件内容生成散列值。

服务端设置响应头

etag: "5cbee451-7818"

客户端下次请求头会携带

if-none-match: "5cbee451-7818"
  1. 强缓存

尽管条件请求可以在文件内容没有修改的情况下节省带宽,但是它依然会发起一个HTTP请求,使得客户端依然会花一定时间来等待响应。可见最好的方案就是连条件请求都不用发起。

在响应里设置Expires或Cache-Control头,浏览器将根据该值进行缓存。

服务端设置响应头

expires: Tue, 31 Dec 2019 08:16:58 GMT

但是Expires的缺陷在于浏览器与服务器之间的时间可能不一致,这可能会带来一些问题,比如文件提前过期,或者到期后并没有被删除。在这种情况下,Cache-Control以更丰富的形式,实现相同的功能

服务端设置响应头

cache-control: max-age=300

清除缓存

虽然我们知晓了如何设置缓存,以达到节省网络带宽的目的,但是缓存一旦设定,当服务器端意外更新内容时,却无法通知客户端更新。这使得我们在使用缓存时也要为其设定版本号,所幸浏览器是根据URL进行缓存,那么一旦内容有所更新时,我们就让浏览器发起新的URL请求,使得新内容能够被客户端更新。一般的更新机制有如下两种。

  1. 每次发布,路径中跟随Web应用的版本号:http://url.com/?v=20130501。
  2. 每次发布,路径中跟随该文件内容的hash值:http://url.com/?hash=afadfadwe。

CDN缓存

image

通过上图,我们可以了解到,使用了CDN缓存后的网站的访问过程为:

  1)、用户向浏览器提供要访问的域名;
  2)、浏览器调用域名解析库对域名进行解析,由于CDN对域名解析过程进行了调整,所以解析函数库一般得到的是该域名对应的CNAME记录,为了得到实际IP地址,浏览器需要再次对获得的CNAME域名进行解析以得到实际的IP地址;在此过程中,使用的全局负载均衡DNS解析,如根据地理位置信 息解析对应的IP地址,使得用户能就近访问。
  3)、此次解析得到CDN缓存服务器的IP地址,浏览器在得到实际的IP地址以后,向缓存服务器发出访问请求;
  4)、若请求文件并未修改,返回304(充当服务器的角色)。若当前文件已过期,则缓存服务器根据浏览器提供的要访问的域名,通过Cache内部专用DNS解析得到此域名的实际IP地址,再由缓存服务器向此实际IP地址提交访问请求;
  5)、缓存服务器从实际IP地址得得到内容以后,一方面在本地进行保存,以备以后使用,二方面把获取的数据返回给客户端,完成数据服务过程;
  6)、客户端得到由缓存服务器返回的数据以后显示出来并完成整个浏览的数据请求过程。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant