页面一直显示 Loading 时,我会从哪里开始查
结合这个 Next.js 项目的结构,整理一套不依赖猜测的加载故障排查顺序。
“本地正常,线上一直 Loading”很容易把人带进猜测:是不是缓存、是不是 Nginx、是不是服务器太慢。猜得越多,真正有用的信息反而越少。
这个网站目前运行在 Next.js Node.js 服务上,前台还会读取 Supabase 配置和内容,所以我更愿意按请求链路从外向内排查。
先确认卡住的是哪一层
第一步不是改配置,而是打开浏览器的 Network 面板。HTML 是否返回?JavaScript 和 CSS 有没有 404?一直 pending 的是页面请求、站内 API,还是 Supabase、天气等外部请求?
如果 HTML 本身就没有返回,就去看 Nginx 和容器状态;如果页面框架已经出现,只是某个模块一直转圈,问题更可能在客户端请求或状态收尾。
docker compose ps
curl -I https://050906.xyz
curl --fail https://050906.xyz/api/health
docker compose logs --tail=100 blog这些命令不能直接给出答案,但能快速区分“应用没启动”“反向代理没转发”和“应用内部某个数据源失败”。
环境变量要分清构建时和运行时
这个项目里,NEXT_PUBLIC_ 变量会被前端代码使用,通常需要在构建镜像时提供;Supabase service role、R2 secret 等敏感值只应在服务端运行时注入。
变量缺失时,页面不应该无休止地等待。可选功能可以显示降级内容,必需配置则应该尽早返回明确错误。比起把地址硬编码进 next.config.ts,我更倾向于保留一份 .env.example,在启动或健康检查时验证必需项。
还要留意浏览器里的请求地址。出现 undefined/api/...、错误域名或 http/https 混用,通常比控制台里一长串后续报错更接近根因。
Loading 必须有退出路径
即使网络失败,组件也应该从加载状态退出。一个常见写法是把收尾放进 finally:
setLoading(true);
try {
const response = await fetch("/api/posts");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
setPosts(await response.json());
} catch (error) {
setError(error instanceof Error ? error.message : "加载失败");
} finally {
setLoading(false);
}对外部服务还应该设置合理超时。天气、公告或个人状态拿不到时,可以暂时不显示;它们不应该拖住整张首页。
修复以后再走一遍真实路径
看到接口返回 200 还不够。我会重新开一个无缓存窗口,检查首页首屏、文章详情、搜索和移动端导航,再看日志里有没有不断重试的请求。
排查这类问题最有用的不是记住某个平台的某个坑,而是始终拿证据缩小范围:浏览器告诉我是哪条请求,代理日志告诉我请求去了哪里,应用日志再解释为什么失败。这样下一次部署环境变化,方法仍然能用。