数据库里只有 1 行且 updated_at 是最近的——说明保存其实写入成功了,但前端却显示崩溃页。这是典型的:保存成功后做了某个会抛错的操作(比如把响应当 JSON 解析、或刷新触发服务端组件崩溃)。我需要看 API 路由和表单 fetch 的真实代码。让我完整读取这两段。
API 路由完全健壮,且数据库确实更新成功了。崩溃发生在前端保存成功之后的操作。让我完整读取表单的保存流程和成功后的处理(router.refresh 等)。
handleSubmit 末尾的 try/catch/finally 很完整。让me see the fetch part 320-340.
handleSubmit 完全健壮。崩溃"此页面无法加载"是浏览器级硬错误页,更像是服务端页面渲染时崩溃或整页导航出错。同时 WhatsApp 前台未更新,说明前台读取设置的方式有缓存或读错源。让我并行检查:设置页的服务端组件、以及前台读取 settings 的逻辑。
让me find getSiteSettings in lib/data.
我已理清全部问题。有两个独立的 bug:
getSiteSettings(带 cache() + Next 静态缓存),但保存 API 从不调用 revalidatePath,所以前台一直读旧的缓存数据。error.tsx 错误边界,一旦任何渲染期出错,就直接掉到 Next.js 的全局黑屏崩溃页(图中那个"此页面无法加载")。我来分两步修复。先给保存 API 加上前台重新验证。
Now add revalidation after successful update and insert. Let me add a helper that revalidates all front-facing paths, and call it in both success branches.
Let me read the update success branch to add revalidate before its return.
需要给 update 成功分支也加刷新。用更大上下文定位唯一的那一处。
現在解决第二个、也是最关键的问题:全屏崩溃页。整个后台没有 error 边界,任何渲染期错误都会掉到 Next 全局黑屏。我给 admin 区加一个 error.tsx 错误边界,把错误以友好卡片+具体原因展示,而不是黑屏。先看 admin 目录结构和已有 UI 风格。
现在创建 admin 区的错误边界。这样后台任何页面渲染期出错时,会显示一张友好卡片、明确展示错误信息和"重试"按钮,而不是全屏黑屏崩溃页。
現在验证构建。
构建通过。现在还要确保 revalidatePath 在 API 路由中能正常工作——由于 getSiteSettings 用了 React cache()(仅单次请求内缓存),真正的持久缓存来自 Next 的全页静态缓存。让我确认前台页面没有强制静态化导致 revalidate 无效。检查首页配置。
没有显式缓存配置,使用默认行为。revalidatePath 现在能正确刷新这些路径。提交全部改动。
已完成,改动已提交。我诊断出这是两个独立的问题,都已修复。
数据库其实保存成功了(我查过,记录的 updated_at 是最新的),但保存 API 从不刷新前台页面缓存,所以前台一直显示旧值。
revalidatePath 刷新首页、关于页、联系页、车辆页以及根布局(页眉/页脚),改动现在会立即同步到前台。整个后台没有任何错误边界,所以一旦任何渲染期出现异常,就会直接掉到 Next.js 的全局黑屏崩溃页(图中那个)。
app/admin/error.tsx 错误边界。现在后台任何页面出错时,会显示一张友好的卡片,明确弹出具体错误信息和错误编号,并提供"重试""刷新页面"按钮——不再黑屏。这正好满足你的要求:出错时直接显示是什么原因、什么错误,而不是无法加载的黑屏。
建议你刷新后台重新测试一次:保存公司设置应弹出"设置已保存",前台 WhatsApp/电话立即更新;万一仍有错误,也会以红色卡片显示具体原因,请把卡片里的错误信息发给我即可进一步定位。
画面显示的是我新加的错误边界卡片,标题"页面出现错误",错误信息为:未能在"节点"上执行"insertBefore":新节点要插入的节点不是该节点的子节点(即 React 的 Failed to execute 'insertBefore' on 'Node')。同时右下角弹出了"设置已保存,公司信息已更新并同步至前台"的成功提示。
这说明:保存本身完全成功了,崩溃发生在保存成功之后的"刷新/重渲染"阶段。让我看保存成功后的处理逻辑。
错误信息 insertBefore:新节点要插入的节点不是该节点的子节点 是 React 经典的 DOM 协调崩溃,几乎总是由浏览器的"翻译"功能(Google 翻译/Edge 翻译等扩展)引起的。保存成功后会弹出 toast 提示,toast 通过 React Portal 插入 DOM;而翻译插件此时已经改动了页面的文本节点,导致 React 调用 insertBefore 时找不到原本的子节点而崩溃。右下角"设置已保存"证明保存逻辑没问题,崩的是这次重绘。
让我查看根布局,加入针对该问题的标准防护。
错误根因已确定:insertBefore ... 不是该节点的子节点 是 React 与**浏览器翻译插件(Google/Edge 翻译)**冲突导致的经典崩溃。保存成功后弹出的 toast 通过 React Portal 插入 DOM,而翻译插件此时已经替换了页面里的文本节点,React 找不到原节点就崩溃了——右下角"设置已保存"恰好证明保存本身没问题。
最佳修复:让后台管理区不被自动翻译(后台是内部使用,无需翻译;前台多语言不受影响)。我来在 admin 布局加 translate="no" + notranslate。先读取当前 admin 布局结构。
我给后台整个区域包一层带 translate="no" 和 notranslate 类的容器,告诉浏览器翻译插件不要翻译后台界面,从根源消除 React DOM 冲突。后台是内部管理工具无需翻译,前台多语言完全不受影响。
此外,为了进一步降低 toast 与 DOM 协调冲突的风险,我让保存成功的 toast 延后一帧再弹(让 React 先完成本次 state 提交),并加固一下。但更关键的防护已经到位。让我验证构建。
构建通过。提交改动。
已找到根因并修复,改动已提交。
注意截图右下角的提示:"设置已保存,公司信息已更新并同步至前台"——说明你的公司资料其实保存成功了,数据已写入数据库并同步到前台。崩溃发生在保存之后。
错误信息 未能在"节点"上执行"insertBefore":新节点要插入的节点不是该节点的子节点,是 React 一个非常典型的崩溃,几乎总是由浏览器的网页翻译功能引起的(比如 Chrome 的"翻译成中文"、Edge 翻译,或翻译类插件)。
原理:翻译插件会偷偷替换页面上的文字节点。当你点保存、成功后弹出"设置已保存"提示时,React 需要往页面里插入这个提示框,但此时原本的节点已经被翻译插件改掉了,React 找不到它,就抛出了 insertBefore 错误。
我在整个后台管理区加上了 translate="no" 标记,明确告诉浏览器翻译插件不要翻译后台界面。后台是你自己内部使用的管理工具,本来就不需要翻译,所以这样最干净,而前台网站的多语言功能完全不受影响。
现在你保存公司资料应该不会再崩溃了。如果你之前手动开启过对该页面的翻译,建议刷新一次页面让设置生效。如仍有问题,也可以临时关闭浏览器的翻译功能再测试。