fix(profile): /u/[username] SSR 抓取加重试 + 添加 error 边界#286
Conversation
线上偶发"Application error: a server-side exception has occurred"报错(digest 3734429282)。
Vercel runtime logs 定位到 GET /api/user-center/profile/{id} 收到 Cloudflare 403(直连后端 200),
疑似 Vercel SSR 出口被 CF Bot/Managed Challenge 偶发拦截。单次 403 直接冒泡到 Next 默认错误页,
用户体验就是白屏 + digest。
两处改动:
1) app/u/[username]/page.tsx — fetchProfile 加重试 + 诊断日志
- 首次走 ISR(300s),失败后两次 cache:"no-store" 重试(300ms/800ms 退避),绕开 Data Cache
把 403 粘住 5 分钟的问题
- 显式带 UA / Accept header,降低被 CF 判 bot 概率
- 每次非 2xx 都记录 status / cf-ray / cf-mitigated / content-type / 响应体前 300 字符,
下次再发生时 Vercel 日志里直接有证据(原先只在 dev 打 warn)
2) app/u/[username]/error.tsx — 新增路由级错误边界
- 取代 Next 默认的白屏错误页,给出"重试 / 返回首页 / 排行榜"三个出口
- 展示 digest 让用户可以回贴排查
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
该 PR 旨在修复 /u/[username] 个人主页在 Vercel SSR 场景下偶发被 Cloudflare 返回 403 导致的“白屏/500 并被 ISR 缓存粘住”问题,并通过路由级 error boundary 提供可恢复的降级 UI。
Changes:
- 为 profile SSR 抓取增加重试(首次走 ISR,失败后两次
no-store重试)并补充诊断日志(cf-ray/响应体片段等) - 新增
/u/[username]路由级error.tsx,替代 Next 默认错误页,提供“重试/返回首页/排行榜”出口
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| app/u/[username]/page.tsx | fetchProfile 增加重试策略、生产日志与 CF 诊断信息,减少偶发 403 被缓存放大的影响 |
| app/u/[username]/error.tsx | 新增路由级错误边界,避免默认 Application error 白屏并提供重试能力 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const bodySnippet = await res | ||
| .text() | ||
| .then((t) => t.slice(0, 300)) | ||
| .catch(() => "<read body failed>"); | ||
| warnFetchProfile("backend non-2xx", { |
There was a problem hiding this comment.
The code logs a bodySnippet (first 300 chars) from upstream responses into server logs. Even though this only happens on non-2xx, those bodies can still contain sensitive data (e.g., backend error pages, stack traces, Cloudflare challenge HTML). Consider redacting/sanitizing this snippet, logging only when content-type is safe/expected, or logging a hash/length instead of raw body content.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
现象
线上访问自己的个人主页(/u/{githubId})偶发报白屏:
定位
Vercel runtime logs 抓到的是:
```
18:29:44 GET /u/114939201 500 Error: profile backend 403
18:36:40 GET /u/114939201 500 Error: profile backend 403
```
但从任意其他位置 `curl https://api.involutionhell.com/api/user-center/profile/114939201\` 都是 200,后端 SaToken 配置里 `/api/user-center/profile/**` 也在白名单。
结论:单次 403 来自 Cloudflare 对 Vercel SSR 出口的偶发拦截(疑似 Bot Fight / Managed Challenge),不是后端本身问题。叠加 `fetch` 的 `next: { revalidate: 300 }`,一次 403 会被 Next Data Cache 粘住 5 分钟,把问题放大成"持续白屏"。
修复
`app/u/[username]/page.tsx` — fetchProfile 带重试 + 诊断日志
`app/u/[username]/error.tsx` — 新增路由级 error 边界
不在这个 PR 里的事
Test plan