diff --git a/gvsds/apps/core/views.py b/gvsds/apps/core/views.py index 53558e2d..9ab37e6f 100644 --- a/gvsds/apps/core/views.py +++ b/gvsds/apps/core/views.py @@ -1,4 +1,5 @@ import os +import re import mimetypes from pathlib import Path from django.http import HttpResponse, Http404, JsonResponse, HttpResponseRedirect @@ -8,6 +9,14 @@ from gvsds.template_engine import render_template TEMPLATE_DIR = Path(settings.BASE_DIR) / "TempLate" +#: 构建产物(Vite 输出 -.)的强缓存时长:72 小时 +#: 依据:文件名内含内容 hash,内容与名字一一对应;新版本会换新文件名, +#: 因此不会出现「改了代码但客户端还是旧文件」的问题(index.html 仍为 no-cache)。 +HASHED_ASSET_MAX_AGE = 60 * 60 * 72 +#: 识别构建产物名:-<8 位以上 hash>.,且 hash 段须含大写字母或数字 +#: (避免误伤 gvs-design-system.css 这类全小写连字符的传统文件名) +HASHED_ASSET_RE = re.compile(r'-(?=[A-Za-z0-9_-]*[A-Z0-9])[A-Za-z0-9_-]{8,}\.[A-Za-z0-9]+$') + MIME_TYPES = { '.js': 'application/javascript', '.mjs': 'application/javascript', @@ -152,7 +161,12 @@ def _serve_file(full_path, subdomain=None): with open(full_path, 'rb') as f: response = HttpResponse(f.read(), content_type=content_type) - if ext in ('.css', '.js', '.mjs', '.json', '.xml', '.txt', '.svg'): + if HASHED_ASSET_RE.search(full_path.name): + # Vite 构建产物(如 index-C_-1ws_N.js / style-BWB-O5Ko.css): + # 文件名含内容 hash,路径随版本变化,可长期强缓存 + immutable 免协商 + response['Cache-Control'] = f'public, max-age={HASHED_ASSET_MAX_AGE}, immutable' + elif ext in ('.css', '.js', '.mjs', '.json', '.xml', '.txt', '.svg'): + # 非 hash 命名的传统静态资源(legacy 站点),改动后需较快生效 response['Cache-Control'] = 'public, max-age=3600' elif ext in ('.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.woff', '.woff2', '.ttf', '.eot', '.mp4'): response['Cache-Control'] = 'public, max-age=86400'