部分由浏览器缓存

时间:2016-01-30 13:02:31

标签: javascript angularjs

我已经构建了一个基于指令的AngularJS HTML5应用程序。每个指令都将使用templateUrl语法从另一个文件加载它的模板。

该应用程序是一个单页面应用程序,让我们假装它可以通过http://prod/index.html访问,当加载该页面时,指令将加载http://prod/partials/directive-a.html

在将新版本的网站推送到我的生产环境时,我遇到了问题。浏览器继续使用先前版本的缓存资产。

例如,如果我导航到http://prod,则会显示以前版本中的所有资产。如果我强制刷新页面(CTRL+F5),将从服务器重新加载index.html页面并反映任何更改。

导致浏览器刷新partials/directive-a.html。因此,新的index.html页面仍会显示旧的directive-a.html

如果我导航到浏览器地址栏中的完整部分HTML文件(partials/directive-a.html),则会向我显示旧版本的部分。通过对部分页面进行硬刷新,将显示部分页面的正确(新)版本,并在重新加载index.html上的指令时进行更新。

我可以使用哪些机制来阻止部分缓存?

我见过关于在查询参数中添加时间戳的评论,但这似乎过于笨重地放在我的所有指令和路由上。

2 个答案:

答案 0 :(得分:2)

@Duncan为您提供了处理模板的绝佳方式,但我认为这不是唯一的问题。请记住缓存jscssindex.html

简单解决方案 如果您想要缓存问题的简单(几乎理想)解决方案,您可以强制服务器在第一次请求时设置会话cookie(对于index.html)。浏览器会将htmljs缓存为会话长度。您仍然可以获得部分缓存支持而且没有任何问题。

# First response header will set session id:
Set-Cookie:JSESSIONID=0E9AAA7D661A3E100C8EE9F421541B91; Expires=Sun, 29-Jan-2017 14:25:25 GMT; Path=/; HttpOnly

# Next browser request will contain session id from first response.
Cookie:JSESSIONID=0E9AAA7D661A3E100C8EE9F421541B91

复杂的解决方案

您应该考虑使用自定义标头来提供Angular资源。您可以在mod_expires内使用apache

ExpiresByType text/html                             "access plus 0 seconds"
ExpiresByType application/javascript                "access plus 0 seconds" 
ExpiresByType text/css                              "access plus 0 seconds"
...

此解决方案的问题是丢失缓存机制。返回用户不会更快地加载您的网站,您的服务器将体验更多的使用。你可以遇到性能问题。

您可以通过构建机制来改进此解决方案:

  1. 将您的应用js汇总到application.js
  2. minify / uglify application.js
  3. application.js更改为application.[unique-id].js
  4. 更改index.html
  5. 中的出现次数

    同样适用于css和第三方图书馆。

    之后你就可以改变了

    ExpiresByType text/html                             "access plus 0 seconds"
    ExpiresByType application/javascript                "access plus 1 year" 
    ExpiresByType text/css                              "access plus 1 year"
    ...
    

    显然,有基于GruntGulp的自动化解决方案。就个人而言,我可以推荐https://github.com/yeoman/generator-angular

    这两种解决方案都适用于我目前的应用程序。

答案 1 :(得分:1)

我还没有通过测试来查看这是否有效(通过快速Google搜索找到),尽管我认为应该这样做。它正在装饰$http服务,以便任何请求都有一个缓存添加到URL的缓存。您可能希望将逻辑更改为仅装饰'partials/'文件夹中的URL。

anglar.module('myApp',['ui']).config(["$provide", function($provide) {
    return $provide.decorator("$http", ["$delegate", function($delegate) {
        var get = $delegate.get;
        $delegate.get = function(url, config) {
            // Check is to avoid breaking AngularUI ui-bootstrap-tpls.js: "template/accordion/accordion-group.html"
            if (!~url.indexOf('template/')) {
                // Append ?v=[cacheBustVersion] to url
                url += (url.indexOf("?") === -1 ? "?" : "&");
                url += "v=" + cacheBustVersion;
            }
            return get(url, config);
        };
        return $delegate;
    }]);
}]);

来自https://gist.github.com/ProLoser/6181026

或者将所有部分编译成单个templates.js文件,该文件填充模板缓存,然后根本没有模板的实际http请求。如果您使用gulp构建应用程序,则可以使用各种插件模块(例如gulp-angular-templatecachegulp-angular-templates)。