且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何强制浏览器重新加载缓存的CSS和JavaScript文件

更新时间:2022-05-09 00:05:34

对于大约2008年的网站,现有的30多个答案是不错的建议.但是,对于现代的 单页应用程序 (SPA),可能是时候重新考虑一些基本假设了……尤其是这样的想法,即Web服务器***只提供文件的单个最新版本.

The 30 or so existing answers are great advice for a circa 2008 website. However, when it comes to a modern, single-page application (SPA), it might be time to rethink some fundamental assumptions… specifically the idea that it is desirable for the web server to serve only the single, most recent version of a file.

假设您是浏览器中已加载SPA版本 M 的用户:

Imagine you're a user that has version M of a SPA loaded into your browser:

  1. 您的 CD 管道部署了新版本的 N 应用程序到服务器上
  2. 您在SPA中导航,该SPA将 XMLHttpRequest (XHR)发送到服务器以得到/some.template
  1. Your CD pipeline deploys the new version N of the application onto the server
  2. You navigate within the SPA, which sends an XMLHttpRequest (XHR) to the server to get /some.template

  • (您的浏览器尚未刷新页面,因此您仍在运行版本 M )
    • (Your browser hasn't refreshed the page, so you're still running version M)
  1. 服务器以/some.template的内容作为响应-您是否希望它返回模板的版本 M N ?
  1. The server responds with the contents of /some.template — do you want it to return version M or N of the template?

如果/some.template的格式在版本 M N 之间更改(或者文件已重命名或其他名称)您可能不希望版本 N 发送到运行解析器旧版本 M 的浏览器.†

If the format of /some.template changed between versions M and N (or the file was renamed or whatever) you probably don't want version N of the template sent to the browser that's running the old version M of the parser.†

满足两个条件时,Web应用程序就会遇到此问题:

Web applications run into this issue when two conditions are met:

  • 在初始页面加载后的某个时间异步请求资源
  • 应用程序逻辑假定有关资源内容的事情(在将来的版本中可能会发生变化)

一旦您的应用程序需要并行提供多个版本,就可以解决缓存和重载"问题.变得微不足道:

Once your application needs to serve up multiple versions in parallel, solving caching and "reloading" becomes trivial:

  1. 将所有站点文件安装到版本目录中:/v<release_tag_1>/…files…/v<release_tag_2>/…files…
  2. 设置HTTP标头以使浏览器永远缓存文件

  • (或者更好的是,将所有内容都放入CDN中)
  1. 更新所有<script><link>标记等,以指向版本化目录之一中的该文件
  1. Update all <script> and <link> tags, etc. to point to that file in one of the versioned directories

最后一步听起来很棘手,因为可能需要为服务器端或客户端代码中的每个URL调用URL构建器.或者,您可以巧妙地使用 <base>标记并在一处更改当前版本.

That last step sounds tricky, as it could require calling a URL builder for every URL in your server-side or client-side code. Or you could just make clever use of the <base> tag and change the current version in one place.

†一种解决方法是在发布新版本时强制浏览器重新加载所有内容.但是,为了让任何正在进行的操作完成,可能仍然最容易并行支持至少两个版本:v-current和v-previous.

† One way around this is to be aggressive about forcing the browser to reload everything when a new version is released. But for the sake of letting any in-progress operations to complete, it may still be easiest to support at least two versions in parallel: v-current and v-previous.