Skip to content

perf: 修复跨站读取书签并全面优化导入、启动与渲染 - #1

Merged
heropml merged 4 commits into
mainfrom
claude/optimization-review-ablio4
Oct 3, 2026
Merged

heropml merged 4 commits into
mainfrom
claude/optimization-review-ablio4

Conversation

@heropml

@heropml heropml commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

概要

本 PR 修复一个隐私问题:其他网站可以用 <script src="http://127.0.0.1:8765/data.js"> 读出本地服务里的全部私人书签。同时优化了 HTML 导入、启动、页面加载和运行时性能,并新增 CI 测试工作流。

改动

安全

  • 所有响应加上 Cross-Origin-Resource-Policy: same-origin。
  • 拒绝其他网站对文件和接口的非导航请求(Sec-Fetch-Site 为 cross-site / same-site)。从其他网站点链接打开主页不受影响。

正确性

  • HTML 导入改用标准库 html.parser 按标签解析:整份文件写在一行、HREF 不是第一个属性、<H3> 标题跨行的导出文件都能识别。原来这几种情况会解析出 0 条。
  • 解析不到任何书签时拒绝替换现有主页。
  • 去重只作用于页面数据,不再按行删除并改写 data/bookmarks.html。
  • macOS 从主页导入 HTML 时改用 osascript 弹出选择文件窗口,不再在 HTTP 工作线程里创建 Tk 窗口;缺少 tkinter 时按同步失败返回。
  • 分类整理拖拽时,被拖的分类保持半透明直到松开(原来经过其他分类时就被清掉了)。

启动与加载

  • 本地服务启动时跳过 http.server 自带的反向 DNS 解析(socket.getfqdn)。这一步在监听端口之前执行,macOS 上首次解析可能卡住十几秒,超过启动器等待页面的约 4 秒。
  • 快捷方式启动时,只在书签源文件或程序版本变化后才重建 web/data.js;内容不变时不改写,写入改为原子替换。
  • macOS 安装版只在应用更新后才复制资源,复制改为整文件替换。
  • 本地服务启用 HTTP/1.1 keep-alive;POST 回复带 Connection: close。
  • 输出 index.html 时给 css/、js/ 资源地址加 ?v=<修改时间-大小>,带当前版本号的资源长期缓存。
  • /__favicon 改为 ETag 协商,不再每次传约 100KB。
  • 备份列表用正则计数代替完整解析,并缓存结果(20 份 × 8000 条:约 1.1 秒 → 约 0.06 秒)。

运行时

  • 天气改为对冲请求:主源失败或 1.5 秒内没有结果才请求本地备用源,任一成功后取消其余请求;服务端对同一城市的结果缓存 5 分钟。
  • 换主题后约 0.8 秒才同步一次快捷方式图标;服务端遇到相同图标不再启动 cscript 重写。
  • 重新渲染不再重播卡片入场动画,关闭"动态效果"时也不播放。
  • 搜索关键词只拆分一次;搜索时不重建置顶区;分类名先统一测量再统一修改;普通按键不再扫描全部卡片。
  • 背景动画最多 60 帧,慢速特效和后台窗口 30 帧;星芒拖尾去掉逐粒子 shadowBlur;窗口缩放时按帧重建画布。
  • 时钟复用 Intl.DateTimeFormat,日期文字每分钟最多更新一次。

其他

  • 当前版本无法使用的外观方案(例如引用了已移除的主题)会被隐藏并原样保留,不再导致全部方案无法读取。
  • ZIP 升级成功后只保留最近 5 份程序备份。
  • 新增 .github/workflows/tests.yml,在 Ubuntu、Windows、macOS 上运行前端和 Python 测试。
  • ZIP 启动测试失败时会附带服务端输出和最后一次请求的错误,便于在 CI 上定位原因。
  • README 与 web/README.md 已同步更新。

行为变化

  • 主天气源正常时,打开页面只请求一路上游,不再同时请求两路。原有两个测试把"总是请求两路"写成了预期,已按新行为更新。
  • 重复网址不再从 data/bookmarks.html 中删除,只在页面上显示一次。
  • 新增本地文件 data/.data-build.json,记录 data.js 的生成来源,已加入 .gitignore。
  • data/.update-backups/ 不再永久保留,升级成功后只保留最近 5 份。

验证

  • CI 在 Ubuntu、Windows、macOS 上全部通过:前端测试 159 个,Python 测试 160 个。每项改动都有对应的新测试。
  • macOS CI 上原有的 ZIP 启动测试曾两次失败(服务进程在 15 秒内从未响应)。本地注入一个耗时 20 秒的 socket.getfqdn 可以复现同样的失败;跳过反向解析后,该测试 0.1 秒内通过。新增的启动测试在旧代码上失败、在新代码上通过。
  • 用无头 Chromium 实测:
    • 另一来源的页面加载 data.js,服务端返回 403,页面读到 null;主页自身正常显示书签。
    • 主页第二次打开时,34 个 CSS/JS 全部走缓存,不再发请求。
    • 一行式 HTML 导出的 180 条书签全部正确导入。

合并前需要确认

  • 本 PR 的 CI 在 Ubuntu、Windows、macOS 上全部通过
  • macOS:从主页选择"其他浏览器 HTML"导入一次,确认选择文件窗口正常弹出
  • Windows:页面内"重启书签"和在线升级各走一遍(keep-alive 下的重启流程)
  • 发布前同步调高 scripts/manage.py 与 web/index.html 的版本号(本 PR 未改版本号,ZIP 升级通道只识别更高版本)

🤖 Generated with Claude Code

https://claude.ai/code/session_01GeH3G1X7FrWZhYQEPmR9Gr

claude and others added 4 commits October 3, 2026 03:09
安全
- 所有响应加 Cross-Origin-Resource-Policy: same-origin,并拒绝其他网站
  (Sec-Fetch-Site 为 cross-site/same-site 的非导航请求)读取文件和接口,
  其他网页不能再用 <script src=".../data.js"> 读出私人书签

正确性
- HTML 导入改为按标签解析:一行式导出、HREF 不是首个属性、标题跨行都能识别;
  解析不到书签时拒绝替换现有主页;去重只作用于页面数据,不再改写源文件
- macOS 从主页导入 HTML 改用 osascript 选择文件,不在工作线程创建 Tk 窗口;
  缺少 tkinter 时作为同步失败返回
- 分类整理拖拽时被拖分类保持半透明直到松开

启动与加载
- 快捷方式启动只在书签源或程序版本变化时重建 data.js;内容不变时不改写,
  写入改为原子替换
- macOS 安装版只在应用变化时复制资源,复制时整文件替换
- 本地服务启用 HTTP/1.1 keep-alive;index.html 中的 CSS/JS 加版本戳并长期缓存,
  再次打开不再逐个重新验证 34 个资源;favicon 改为 ETag 协商
- 备份列表用计数代替完整解析,并缓存结果

运行时
- 天气改为对冲请求:主源失败或 1.5 秒无结果才请求备用源,成功后取消其余请求;
  服务端同城市天气缓存 5 分钟
- 换主题时快捷方式图标防抖,服务端相同图标不再重写
- 重渲染不再重播卡片入场动画,关闭动态效果时也不播放;搜索只拆分一次关键词,
  置顶区搜索时不重建,分类名测量先读后写,普通按键不扫描卡片
- 背景动画最多 60 帧,慢速特效与后台窗口 30 帧;星芒拖尾去掉 shadowBlur;
  窗口缩放按帧重建画布
- 时钟复用格式器,日期每分钟最多更新一次

其他
- 不兼容当前版本的外观方案隐藏并原样保留,不再导致全部方案无法读取
- ZIP 升级成功后只保留最近 5 份程序备份
- 新增 GitHub Actions 测试工作流(Ubuntu/Windows/macOS),更新说明文档

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GeH3G1X7FrWZhYQEPmR9Gr
服务进程未能在时限内响应时,原测试会丢弃它的输出,CI 上无法判断原因。
现在失败信息附带最后一次请求的错误和服务端的 stdout/stderr。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GeH3G1X7FrWZhYQEPmR9Gr
http.server 在监听端口之前会调用 socket.getfqdn 解析 127.0.0.1 的主机名。
macOS 上首次解析可能卡住十几秒,超过启动器等待页面的时间,CI 的 macOS
任务中 ZIP 启动测试也因此在 15 秒内始终连不上服务。这个名字项目里没有用到,
直接使用绑定地址。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GeH3G1X7FrWZhYQEPmR9Gr
- ZIP 升级:清理旧备份失败不再把已应用的升级报告为未完成
- 书签导入:未闭合的 <A> 遇到 <DD> 描述时结束,描述不再拼进标题
- 备份列表:数量按解析去重后计算,与恢复结果一致;缓存随备份删除而清理
- 快捷方式图标:按外观和快捷方式文件状态判断是否重写,外部重建后会重新设置
- 换外观后立即关闭或刷新页面时,用 keepalive 立即发送图标更新
- 同名重复的外观方案只保留第一份,删除后不再重新出现

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@heropml
heropml merged commit cb53f21 into main Oct 3, 2026
2 of 3 checks passed
@heropml
heropml deleted the claude/optimization-review-ablio4 branch October 3, 2026 04:11

This branch was successfully deployed

1 active deployment
github-pages — cb53f210 Deployed Oct 3, 2026 by heropml via deploy #34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants