diff --git a/README.md b/README.md index 0a8f0ba..7526443 100644 --- a/README.md +++ b/README.md @@ -117,3 +117,7 @@ JSON 导出升级为格式 version 2,包含人物、关系和当前账号有 ### 升级及数据 启动时幂等创建 `family_events` 表,无需修改既有人物、账号、摄像头或录像记录。部署前使用 SQLite backup API 备份数据库。还原备份会回退备份后的数据,旧版本看不到记事表;应保留升级后的数据库备份,不以旧版本界面作为记事恢复工具。源码中不含真实家族记事和人物信息。 + +### 代理缓存兼容(v0.1.17) + +入口 HTML 禁止缓存;页面引用的脚本和样式自动带上发布版本号,避免 NPM 等反向代理为旧资源设置长缓存后,新页面混用旧脚本。升级时普通重新载入即可获取与页面一致的资源。 diff --git a/VERSION b/VERSION index e8e277f..04c5555 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.16 +0.1.17 diff --git a/app.py b/app.py index 2133b97..133fb53 100644 --- a/app.py +++ b/app.py @@ -794,6 +794,8 @@ class Handler(BaseHTTPRequestHandler): raise Problem('页面不存在', 404) file = ROOT / 'web' / files[path] raw = file.read_bytes() + if path == '/': + raw = raw.replace(b'__ASSET_VERSION__', (ROOT / 'VERSION').read_bytes().strip()) self.send_response(200) self.send_header('Content-Type', (mimetypes.guess_type(file.name)[0] or 'application/octet-stream') + '; charset=utf-8') self.send_header('Content-Length', str(len(raw))) @@ -801,7 +803,7 @@ class Handler(BaseHTTPRequestHandler): self.send_header('X-Frame-Options', 'DENY') self.send_header('Referrer-Policy', 'same-origin') self.send_header('Content-Security-Policy', "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; media-src 'self' blob:; worker-src 'self' blob:; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'") - self.send_header('Cache-Control', 'no-cache') + self.send_header('Cache-Control', 'no-store' if path == '/' else 'no-cache') self.end_headers() self.wfile.write(raw) except Problem as e: diff --git a/test_app.py b/test_app.py index fb75585..5db2162 100644 --- a/test_app.py +++ b/test_app.py @@ -72,6 +72,18 @@ class WebTests(unittest.TestCase): self.assertEqual(re.findall(r'', select), [('hd', '主码流'), ('compat', '子码流')]) + def test_asset_urls_follow_release_version(self): + code, headers, body = self.request('/', False) + self.assertEqual(code, 200) + self.assertEqual(headers['Cache-Control'], 'no-store') + self.assertNotIn(b'__ASSET_VERSION__', body) + assets = re.findall(r'(?:src|href)="(/[^"?]+\.(?:js|css)\?v=[^"]+)"', body.decode()) + self.assertEqual(len(assets), 13) + version = (app.ROOT / 'VERSION').read_text().strip() + for asset in assets: + self.assertTrue(asset.endswith('?v=' + version)) + self.assertEqual(self.request(asset, False)[0], 200) + def test_origin_rejected(self): self.assertEqual(self.request('/api/storage', data={}, origin='https://example.org')[0], 403) diff --git a/web/index.html b/web/index.html index 3f8b468..72493f0 100644 --- a/web/index.html +++ b/web/index.html @@ -2,8 +2,8 @@ - 赵府智家 · 家庭空间 - + 赵府智家 · 家庭空间 +