Skip to content

chore(quality): issue #302 剩余 P1 + P2 一锅端#337

Merged
longsizhuo merged 1 commit intomainfrom
chore/issue-302-p1-p2
May 7, 2026
Merged

chore(quality): issue #302 剩余 P1 + P2 一锅端#337
longsizhuo merged 1 commit intomainfrom
chore/issue-302-p1-p2

Conversation

@longsizhuo
Copy link
Copy Markdown
Member

@longsizhuo longsizhuo commented May 6, 2026

背景

issue #302 是 2026-04-13~17 那波 CR 的清单。当时 P0-1 4-17 修了,P2-3 @karicms 4-19 修了。剩 7 条放到现在。这个 PR 一次性清掉 P1×2 + P2×2 共 4 项;P3 的三条(SafeImg / events Suspense / Redis 单例)下次再说。

改动

🟡 P1-1 InterestButton 失败提示

之前 catch {} 把错误吞掉,乐观 UI 回滚后用户看到数字"动了一下又回去"以为按钮坏了。

- } catch {
+ } catch (err) {
    setInterested(prevInterested);
    setCount(prevCount);
+   flashError(err instanceof Error ? err.message : "操作失败,请重试");
  }

flashErroruseState + setTimeout 3 秒自动消失,与 SettingsForm 的 toast 思路一致但内联(按钮位置紧凑,不强插全局 toast)。<span role="alert" aria-live="polite"> 给 a11y 工具 hint。useEffect cleanup 清 timer,避免 setState on unmounted。

🟡 P1-2 Sentry beforeSend 过滤敏感请求头

3 份 Sentry init(client / server / edge)都加:

beforeSend(event) {
  if (event.request?.headers) {
    const h = event.request.headers as Record<string, string>;
    delete h.satoken; delete h.Satoken;
    delete h.cookie;  delete h.Cookie;
    delete h.authorization; delete h.Authorization;
  }
  return event;
}

含大小写变体(HTTP header case-insensitive 但 JS object key sensitive)。错误归类不受影响,只是把凭据从 payload 里抹掉。

🟡 P2-1 EventForm 客户端校验 endTime > startTime

onSubmit 提交前比较:

if (req.startTime && req.endTime && req.endTime <= req.startTime) {
  setError("结束时间必须晚于开始时间");
  setSubmitting(false);
  return;
}

两个 ISO 字符串字典序与时间序一致,可以直接 string compare 不用 new Date()。后端仍是权威,前端这层只防管理员 UI 手抖。

🟡 P2-2 Sentry server / edge 改读 SENTRY_DSN

原来三份 config 都读 NEXT_PUBLIC_SENTRY_DSNNEXT_PUBLIC_ 前缀的 env 会打进客户端 bundle —— client config 必须用 public 那份,server / edge 没必要再暴露一份(DSN 设计上可公开,类似 Stripe publishable key,但留私的更干净)。

- const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN;
+ const dsn = process.env.SENTRY_DSN ?? process.env.NEXT_PUBLIC_SENTRY_DSN;

fallback 是为了兼容当前 Vercel env 还只有 NEXT_PUBLIC_SENTRY_DSN 的情况,迁移期间不丢上报。merge 后可以在 Vercel env 加一份 SENTRY_DSN(同 DSN 值),过段时间删掉 server / edge 的 NEXT_PUBLIC fallback。

验证

  • pnpm exec tsc --noEmit 0 错误
  • pnpm test 19 case 全过(含 i18n matcher 防御测试)

剩下未做

issue #302 上还会留着 3 条 P3:

  • 🟢 P3-1 SafeImg 组件(重复 eslint-disable)
  • 🟢 P3-2 events / feed / events/[id] 改 ISR + client fetch(让它们也 SSG,CPU 边际改善)
  • 🟢 P3-3 rate-limit Redis 实例单例

P3-2 跟今晚 i18n 收尾思路一致,下次有空再开 PR。

清掉 issue #302 还开着的 4 项:

- P1-1 InterestButton 失败提示
  catch 之前静默吞错,乐观 UI 回滚后用户看到数字"动了一下又回去"以为
  按钮坏了。加 inline toast:失败时按钮旁短暂红字(aria-live="polite"),
  3 秒消失,timer 卸载时清掉避免 setState on unmounted。

- P1-2 Sentry beforeSend 过滤敏感请求头
  所有 Sentry init(client/server/edge)加 beforeSend,剔除 satoken /
  cookie / authorization header(含大小写变体),避免凭据原样上报。
  合规 + 缩小攻击面,不影响错误本身的归类。

- P2-1 EventForm 客户端校验 endTime > startTime
  提交前做字典序对比(两个 ISO 字符串字典序与时间序一致),不通过直接
  setError + 阻止提交。后端仍是权威,前端这层只防 UI 手抖。

- P2-2 Sentry server / edge 改读 SENTRY_DSN
  原来三份 config 都读 NEXT_PUBLIC_SENTRY_DSN,server / edge 用 public
  env 没必要。改为优先 SENTRY_DSN,fallback NEXT_PUBLIC_SENTRY_DSN 兼
  容旧部署,迁移期间不丢上报。

剩下未做(issue 还会留着):
- P3-1 SafeImg 组件(重复 eslint-disable,重构属性)
- P3-2 events/feed/events-id 改 ISR + client fetch(CPU 边际改善)
- P3-3 rate-limit Redis 单例
Copilot AI review requested due to automatic review settings May 6, 2026 18:03
@vercel
Copy link
Copy Markdown

vercel Bot commented May 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
involutionhell-github-io Ready Ready Preview, Comment May 6, 2026 6:19pm
website-preview Ready Ready Preview, Comment May 6, 2026 6:19pm

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.

1 participant