目录

    为了快速地响应用户的需求、满足运营活动的需要,互联网产品通常有着非常高的发布频率。采用敏捷开发的方式,缩短了交付的周期,加快了产品的迭代,也给项目的文件管理带来了挑战。前端工程直接面向用户,首当其冲,最值得重视。频繁更新的图片、样式、交互,不同的版本文件,怎样保证用户获取一个可预期的结果呢?本文正是从这个问题出发,讨论相关的解决方案。

    1. 缓存方式

    前端缓存分为两种:

    • 强缓存:浏览器在加载静态资源时,检查 Http Response Header 的 Expires 和 Cache-Control 两个字段。如果在有效期,那么使用浏览器缓存。
    • 协商缓存:如果没有命中强缓存,浏览器会向服务器验证是否命中协商缓存。协商缓存实际上是在静态资源的 Header 上标记 Last-Modified、ETag,通过对比浏览器端、服务器端静态资源的这些值,判断是否是同一个文件。如果一致,则返回 304,Not Modified 表示命中协议缓存。否则,浏览器从服务器加载静态文件。

    服务器缓存主要是 CDN 缓存:

    CDN ,也就是内容分发网络,是在现有网络的基础上,新增一层架构,提前将静态文件,分发到用户访问最佳的网络节点。当用户使用浏览器访问静态资源时,静态资源域名通过 DNS 解析,根据用户的地理位置,返回一个最佳访问的节点 IP 地址。浏览器拿到 IP 地址之后,再请求静态资源。

    2. 强制刷新缓存方式

    强制刷新缓存是指:当缓存有效时,通过一定的技术手段,迫使浏览器不使用缓存,而从服务器请求静态资源。

    主要有两种方式:

    • 重新命名静态资源,如: app.js 更新为 app.a232nas9.js
    • 静态资源链接添加变化的参数,如:app.js 更新为 app.js?v=20171017

    在大型 Web 项目中,更倾向于使用第一种,重命名静态资源的方式实现静态资源的强制刷新。这是由于采用第二种方式,发布时,需要替换静态资源文件。文件替换时,CDN 不能即时完成更新。当仅部分静态资源完成更新时,如果有用户访问,会导致一些不可预期的错误。

    下面介绍几种 Django 中实现的静态文件版本管理的方式:

    2.1 通过 settings 中的变量管理版本

    1,在 yourapp 下新建 context_processors.py 文件

    context_processors.py

    # -*- coding: utf-8 -*-
    from django.conf import settings
    
    def version(request):
        return {
            'VERSION': settings.VERSION
        }
    

    2,修改 settings.py 文件,新增如下内容:

    VERSION = '.1.0.0'
    TEMPLATES = [
        {
            'OPTIONS': {
                'context_processors': [
                    'yourapp.context_processors.version',
                ],
            },
        },
    ]
    

    3、修改 html 中静态资源的引入方式

    静态资源重新命名方式

    <script src="${STATIC_URL}js/app${VERSION}.js"></script>
    <link href="${STATIC_URL}css/app${VERSION}.css" rel="stylesheet">
    

    静态资源链接添加变化的参数方式

    <script src="${STATIC_URL}js/app.js?v=${VERSION}"></script>
    <link href="${STATIC_URL}css/app.css?v=${VERSION}" rel="stylesheet">
    

    每次发布之前,通过修改 settings.py 中 VERSION 变量的值,可以达到前端版本更新的目的。由于静态文件共用一个 VERSION 标识,如果仅仅更新了一个静态文件,其他带上 VERSION 标识的静态文件也将被更新。

    2.2 使用 ManifestStaticFilesStorage

    Django 中提供 ManifestStaticFilesStorage 类,允许 Django 从 staticfiles.json 文件中读取静态文件映射。staticfiles.json 中保存了类似访问 app.css 时,返回 app.s23324a.css 的对应关系。

    1,settings.py 设置

    STATIC_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
    STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
    DEBUG = False
    

    通过对 ManifestStaticFilesStorage 类的继承,复写相应的函数,还可以定制化静态文件名。

    2,修改 html 中静态资源的引入方式

    {% load static %}
    <link href="{% static "css/app.css" %}" rel="stylesheet">
    

    3,收集静态文件

    python manage.py collectstatic
    

    这样在 static 目录下 就会生成一个 staticfiles.json 文件。

    访问网页时,静态文件会被带上 hash 版本值。

    <link rel="stylesheet" type="text/css" href="/static/v/css/base.f0d165989b77.css" />
    <link rel="stylesheet" type="text/css" href="/static/v/css/dashboard.4898e2e9983d.css" />
    

    2.3 使用 CachedStaticFilesStorage

    Django 中提供 CachedStaticFilesStorage 类,允许 Django 从缓存中读取静态文件映射。与 ManifestStaticFilesStorage 不同的是 CachedStaticFilesStorage 不需要创建一个映射文件,而是通过缓存来保存映射关系。

    1,settings.py 设置

    STATIC_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
    STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.CachedStaticFilesStorage'
    DEBUG = False
    

    通过对 ManifestStaticFilesStorage 类的继承,复写相应的函数,还可以定制化静态文件名。

    2,设置缓存

    # 设置 memcache 或者 redis 缓存
    CACHES = {
        "default": {
            "BACKEND": "redis_cache.cache.RedisCache",
            "LOCATION": "127.0.0.1:6379:1",
            "OPTIONS": {
                "CLIENT_CLASS": "redis_cache.client.DefaultClient",
            }
        }
    }
    

    2,修改 html 中静态资源的引入方式

    {% load static %}
    <link href="{% static "css/app.css" %}" rel="stylesheet">
    

    3,收集静态文件

    python manage.py collectstatic
    

    这样在 static 目录下 就会生成一个 staticfiles.json 文件。

    3. 参考