生成器可检测与管理远端主题素材(列表 / 差异 / 覆盖 / 删除)
「传上去」之后还得知道「传得对不对」:同一 slug 传过三次、换过 slug 旧图还在、 重新导出后远端仍是旧版,这些在页面上都看不出来。 - serve.py:s3_request 支持 query;新增 ListObjectsV2(含分页)与 DeleteObject, 端点 /api/s3/list、/api/s3/delete。 - index.html:远端素材清单按对象键名跟本地比 —— 一致 / 旧图(同名但大小不同)/ 多余(当前主题已不引用)/ 缺失。「补齐差异」只传缺的与旧图,「删除多余」批量删, 单行可 ↻ 覆盖或 ✕ 删除;删除走 confirm 二次确认。改过 slug 会提示重新检测。 - 修:list 返回完整键而 upload/delete 收相对键,不剥前缀会删到不存在的键 (S3 回 204,看起来删成功其实没删)。加 relKey() 统一。 - check_sigv4.py 补带 query 的用例(ListObjectsV2 三参数、乱序 token)→ 8/8; selftest_upload.py 补列表/分页/幂等删除 → 20 项全过。
This commit is contained in:
@@ -573,3 +573,30 @@ base.css 还原成 CRLF,插入行要用同一行尾,否则变 MIXED。
|
||||
细节与取舍写进新文档 `docs/theme-assets-cdn.md`(含缓存、CORS、深色无素材、迁移 sed 命令)。
|
||||
⚠️ UI 坑:面板 240px 里 4 个中文字的 label 会被 flex 压缩、末字被输入框切掉 →
|
||||
label 要 `flex:0 0 auto; white-space:nowrap`,宽度给 84px 才够(68px 仍会切)。
|
||||
|
||||
**3) 素材托管:本地 / 任意 S3 兼容,生成器内测通即可上传**
|
||||
用户要求「放本地还是放 S3 兼容(不只 R2)由部署者自己定,并且能配好即测、测通即传」。
|
||||
- `serve.py` 手写 SigV4(零依赖,PUT/GET/DELETE/HEAD),新增 `/api/s3/ping|test|upload`。
|
||||
测试连接四步:HEAD 桶 → PUT 探针 → GET 读回比对 → 匿名 GET(能否被浏览器直读)→ 删探针。
|
||||
4xx 把 `<Code>` 翻成人话(`S3_HINTS`),签名失败直接指向密钥/Region/时钟三件事。
|
||||
- `index.html` 新增「素材托管」面板,上传集合复用导出用的 `usedAssetIds()`;
|
||||
成功后自动回填「素材前缀」。密钥只进 sessionStorage,不进工程 json(有断言)。
|
||||
- **两个真 bug**:①`usedAssetIds()` 返回 Set,`!ids.length` 恒真 → 永远「还没有素材」;
|
||||
②字段填完 700ms 内刷新会丢(scheduleSave 防抖)→ 失焦/切模式/上传成功时立即 `saveDraft()`。
|
||||
- **验证手段**:`check_sigv4.py` 用 aws-sdk-go-v2 的 signer 逐字节对拍(6/6)——
|
||||
裸 SignHTTP 会二次转义 URI、而 S3 client 关了它,所以用例只用 ASCII,
|
||||
中文 key 的编码规则跟随 S3 client(单次 RFC3986)。
|
||||
`selftest_upload.py` 假 S3 跑 16 项;`mock_s3.py` 可手动点面板。
|
||||
- ⚠️ **8777 端口陷阱**:Windows `SO_REUSEADDR` 让新进程 bind 成功却抢不到 accept,
|
||||
症状是「代码改了但接口还是 404」。查 `Get-NetTCPConnection -LocalPort 8777`,或换端口验证。
|
||||
|
||||
**4) 远端素材检测与管理(用户「还没测,想先看到 S3 上有什么」)**
|
||||
- serve.py:`s3_request` 支持 query,新增 `list_objects`(ListObjectsV2 + 分页)与
|
||||
`delete_objects`;端点 `/api/s3/list`、`/api/s3/delete`。
|
||||
- index.html:远端素材区,按对象键名跟本地比 → 一致 / 旧图(同名大小不同)/ 多余 / 缺失;
|
||||
「补齐差异」只传缺的与旧图,「删除多余」批量删,单行 ↻ 覆盖、✕ 删除。
|
||||
- ⚠️ **键的两种形态**:list 返回**完整键**(含 `<路径前缀>/`),upload/delete 接口收
|
||||
**相对键**。不剥这一层,服务端会再拼一次前缀 → 删一个不存在的键,S3 还回 204,
|
||||
表现为「显示删除成功但东西还在」。加 `relKey()` 统一转换。
|
||||
- ⚠️ `check_sigv4.py` 补了带 query 的用例(ListObjectsV2 三参数、乱序传入的分页 token),
|
||||
8/8 一致 —— canonical query 的排序与百分号编码也必须对拍,漏测会静默失效。
|
||||
|
||||
@@ -44,3 +44,27 @@
|
||||
- 导出面板「素材前缀」`S.assetBase`:空 = `/static/images/themes/<slug>/`;填了 = CSS 写绝对 URL
|
||||
(R2/OSS)。**图片地址只能由 `urlOf()` 决定** —— `layerCSS` 曾复制过一份拼接,改一处会出现
|
||||
「背景走 CDN、装饰还指本地」。文档见 `docs/theme-assets-cdn.md`。
|
||||
- **素材托管(2026-10-21)**:面板两选一 `S.host.mode = local|s3`,字段
|
||||
endpoint/region/bucket/prefix/pathStyle/publicBase 进工程,**accessKey/secretKey 只进
|
||||
sessionStorage**(`SEC_SESSION_KEY`),绝不进草稿/工程 json/导出 zip(有断言)。
|
||||
`publicBaseOf()` 手填优先,空则按 endpoint 推导(path 风格 `<ep>/<桶>/<前缀>`)——
|
||||
对 R2 这个地址不可匿名读,测试的「匿名可读」只给 warn 不拦。
|
||||
- **上传走 `serve.py` 代理**,浏览器不直连对象存储:不用配 CORS,密钥不发给第三方。
|
||||
端点 `/api/s3/ping`(探测能力,`python -m http.server` 没有 → 按钮禁用)、
|
||||
`/api/s3/test`、`/api/s3/upload`。上传集合与导出共用 `usedAssetIds()`。
|
||||
- ⚠️ **`usedAssetIds()` 返回 Set**:`!ids.length` 恒真、`ids.map` 不存在 → 上传永远报
|
||||
「还没有素材」。用 `[...usedAssetIds()]` 展开。
|
||||
- ⚠️ **SigV4 手写,必须对拍**:`dev/theme-builder/check_sigv4.py` 调
|
||||
`dev/sigv4ref`(aws-sdk-go-v2 的 `signer.SignHTTP`)逐字节比。6/6 一致才可信。
|
||||
- 只用 ASCII 用例:裸 `SignHTTP` 默认**二次转义** URI,而 S3 client 内部把
|
||||
`DisableURIPathEscaping` 设成 true(单次编码)。我们跟随 S3 client / AWS 文档 RFC3986。
|
||||
- canonical headers 三件套 `host;x-amz-content-sha256;x-amz-date`,与 SDK 相同;
|
||||
CanonicalHeaders 自身以 `\n` 结尾,故其后与 SignedHeaders 之间有一个空行(规范如此)。
|
||||
- ⚠️ **HEAD 桶失败拿不到 `<Code>`**(HEAD 响应无 body)→ 只能按状态码归因
|
||||
(403→AccessDenied / 404→NoSuchBucket / 301|307→PermanentRedirect)。想拿真错误码要靠 PUT。
|
||||
- ⚠️ **Windows 上 8777 可能被上一个进程继续占着**(SO_REUSEADDR 让新进程 bind 成功但抢不到
|
||||
accept)。症状:`/api/s3/ping` 返回旧版 404,而代码明明改了。用
|
||||
`Get-NetTCPConnection -LocalPort 8777` 查 PID,或换端口验证。
|
||||
- 自测:`python dev/theme-builder/check_sigv4.py`(签名对拍)、
|
||||
`python dev/theme-builder/selftest_upload.py`(假 S3,16 项)、
|
||||
`python dev/theme-builder/mock_s3.py --port 9900`(手动点面板)。
|
||||
|
||||
Reference in New Issue
Block a user