feat(assets): 注册 assets_ver() 全局函数(js/css 最大 mtime, 30s 缓存),根治改了前端 js 浏览器仍跑旧代码

This commit is contained in:
yumoqing 2026-08-25 14:36:18 +08:00
parent 16fd5a3530
commit 8a3eb50300

View File

@ -1,8 +1,66 @@
import os
import time
from ahserver.serverenv import ServerEnv
from ahserver.globalEnv import initEnv, password_encode as _password_encode
from appPublic.jsonConfig import getConfig
DBNAME = "pipeline"
# 静态资源缓存版本号:取所有应用级 js/css 与 bricks 主文件的最大 mtime。
# 浏览器对无 Cache-Control 的静态文件走启发式缓存,改了 js 用户仍跑旧代码;
# 这里把 mtime 作为 ?v= 参数注入 header.tmpl部署后自动失效无需手工 bump 版本号。
_ASSETS_VER_TTL = 30
_assets_ver_cache = {'ver': None, 'ts': 0.0}
def _asset_ospaths():
"""把 jsfiles()/cssfiles() 的 url 路径映射回磁盘路径(含 bricks 主文件)。"""
g = ServerEnv()
config = getConfig()
roots = []
for item in (config.website.paths or []):
roots.append(item[0] if isinstance(item, (list, tuple)) else item)
urls = ['/bricks/bricks.js', '/bricks/css/bricks.css']
for name in ('jsfiles', 'cssfiles'):
f = g.get(name)
if not callable(f):
continue
try:
urls += list(f() or [])
except Exception:
pass
for u in urls:
for root in roots:
fp = root + u
if os.path.isfile(fp):
yield fp
break
def assets_ver():
"""静态资源版本号字符串30 秒内复用缓存结果。"""
now = time.time()
if _assets_ver_cache['ver'] and now - _assets_ver_cache['ts'] < _ASSETS_VER_TTL:
return _assets_ver_cache['ver']
mx = 0
try:
for fp in _asset_ospaths():
try:
m = os.path.getmtime(fp)
except OSError:
continue
if m > mx:
mx = m
except Exception:
mx = 0
ver = str(int(mx)) if mx else str(int(now))
_assets_ver_cache['ver'] = ver
_assets_ver_cache['ts'] = now
return ver
def password_encode(s):
"""Wrapper to handle None input during login form load."""
@ -20,3 +78,4 @@ def set_globalvariable():
g = ServerEnv()
g.get_module_dbname = get_module_dbname
g.password_encode = password_encode
g.assets_ver = assets_ver