VueJS /浏览器缓存生成版本

ier*_*dna 26 html browser-cache vue.js

我有一个VueJS应用程序.每当我运行npm run build它时会创建一组新dist/*文件,但是,当我在服务器上加载它们(删除旧版本后),并在浏览器中打开页面时,它会加载旧版本(从我假设的缓存中).当我刷新页面时,它加载新代码没问题.

这是我的index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
        <meta http-equiv="cache-control" content="max-age=0" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="expires" content="-1" />
        <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
        <meta http-equiv="pragma" content="no-cache" />
        <link rel="stylesheet" href="/static/css/bootstrap.min.css"/>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

有没有办法强制它每次加载新代码或(理想情况下)检查旧文件是否从服务器中消失,然后刷新浏览器?

Sea*_*Ray 11

基于这个关于缓存标头的综合答案,如果你可以控制它,你最好的选择是在服务器端解决这个问题,因为<meta>标签中的任何内容都会被服务器设置的标头覆盖。

对该问题的评论表明您正在使用 nginx 为该应用程序提供服务。使用上面链接的答案,我能够在我的 nginx 配置中为以这种方式结尾的文件的任何请求设置Cache-Control,ExpiresPragma标头.html

server {

  ...other config

  location ~* \.html?$ {
    expires -1;
    add_header Pragma "no-cache";
    add_header Cache-Control "no-store, must-revalidate";
  }
}
Run Code Online (Sandbox Code Playgroud)

这成功地强制浏览器index.html在每个页面重新加载时请求最新的,但仍然使用缓存的资产 (js/css/fonts/images),除非最新的 html 响应中有新的引用。


For*_*ame 10

我们在同样的问题上苦苦挣扎,发现有些人的浏览器甚至不会提取最新版本,除非他们手动刷新.我们在各个层面都有缓存问题,包括我们托管文件的CDN.

我们还努力维护版本,并且如果出现问题,我们可以快速重新部署以前的版本.

我们的解决方案(使用基于vue-cli Webpack的项目):

1)我们构建分发版本以具有特定于版本的文件夹而不是"静态".这还有助于我们跟踪构建并在需要时"撤消"部署.要更改"静态"目录,请更改index.js中"build"下的"assetsSubDirectory",并将"assetsPublicPath"更改为CDN路径.

2)我们使用Webpack Assets Manifest来构建指向所有资产的manifest.json文件.我们的清单包括所有文件的哈希值,因为它是一个高安全性的应用程序.

3)我们将版本化文件夹(包含js和css)上传到我们的CDN.

4)(可选)我们在后端服务器上托管动态index.html文件.后端服务器使用从manifest.json上的数据中提取的模板系统填充样式表和脚本的链接(参见#5).这是可选的,因为您可以使用force-reload选项,如下面的注释,这不是一个很好的经验,但确实有效.

5)要发布新版本,我们将manifest.json发布到后端服务器.我们通过GraphQL端点执行此操作,但您可以手动将json文件放在某处.我们将其存储在数据库中并使用它来填充index.html,并使用它来验证使用文件哈希的文件(以验证我们的CDN没有被黑客入侵).

结果:立即更新并轻松跟踪和更改您的版本.我们发现它会立即在几乎所有用户的浏览器中提取新版本.

另一个好处是:我们正在构建一个需要高安全性的应用程序,并且在我们(已经安全的)后端托管index.html使我们能够更轻松地通过我们的安全审核.


编辑2/17/19

我们发现企业网络正在进行代理缓存,尽管没有缓存标头.IE 11似乎也忽略了缓存头.因此,一些用户没有获得最新版本.

我们有一个在构建时增加/定义的version.json.版本号包含在manifest.json中.构建包自动上载到S3.然后我们将manifest.json传递给后端(我们在Admin区域的入口页面上执行此操作).然后,我们在该UI上设置"活动"版本.这使我们可以轻松更改/恢复版本.

后端将"currentVersion"作为响应标头放在所有请求上.如果currentVersion!== version(在version.json中定义),那么我们要求用户单击以刷新他们的浏览器(而不是强制它们).

  • 我想我的痛苦减少了很多.我让客户端请求服务器版本,然后它将当前服务器版本与客户端存储在`localStorage`变量中的版本进行比较.如果它们不同,我会做`window.location.reload(true);`强制浏览器从服务器获取新文件.至少它似乎工作. (16认同)

bra*_*boy 6

这个问题很烦人,毫无疑问。必须使用在标头中发送的自定义前端版本端点来解决它。我使用 rails 后端和 Vue + Axios 作为前端。注意我不需要服务人员,因此不使用服务人员。

本质上,我只是在有获取请求并且应用程序版本已更改时重新加载(服务器可以通知相同)

axiosConfig.js

axios.interceptors.response.use(
  (resp) => {
    const fe_version = resp.headers['fe-version'] || 'default'
    if(fe_version !== localStorage.getItem('fe-version') && resp.config.method == 'get'){
      localStorage.setItem('fe-version', fe_version)
      window.location.reload() // For new version, simply reload on any get
    }
    return Promise.resolve(resp)
  },
)
Run Code Online (Sandbox Code Playgroud)

Rails 后端

application_controller.rb

after_action :set_version_header

def set_version_header
  response.set_header('fe-version', Setting.key_values['fe-version'] || 'default')
end
Run Code Online (Sandbox Code Playgroud)

application.rb (CORS 配置假设 Vue 在端口 8080 上运行)

config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins ['localhost:8080', '127.0.0.1:8080']
    resource '*', expose: ['fe-version'], headers: :any, methods: [:get, :post, :delete, :patch], credentials: true
  end
end if Rails.env.development?
Run Code Online (Sandbox Code Playgroud)

这里写了一篇详细的文章:https : //blog.francium.tech/vue-js-cache-not-getting-cleared-in-production-on-deploy-656fcc5a85fe