hydration failed 根本原因是 nginx 未正确分流请求:/api/ 必须代理至 next.js 后端,/_next/static 等静态资源由 nginx 直接服务,其余请求交由 next.js 处理;顺序错误或配置遗漏会导致客户端与服务端 html 不一致。

Next.js 应用通过 Nginx 托管时出现 Hydration failed because the initial HTML does not match what was rendered on the client,绝大多数情况不是代码问题,而是 Nginx 未正确代理 API 请求或静态资源路径,导致客户端与服务端渲染(SSR/SSG)环境不一致。关键在于:Nginx 必须把浏览器发起的 API 请求(如 /api/xxx)准确转发给 Next.js 后端(如 https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4),同时让静态文件(/_next/)直接由 Nginx 服务,且不干扰 React 的客户端路由。
确保 Next.js 运行在标准端口并启用输出静态化(推荐)
部署前,在 next.config.js 中明确配置输出模式:
- 若使用
output: 'standalone'(Next.js 13.5+),构建后会生成独立可运行的.next/standalone目录,内含精简 Node server —— 此时你仍需用 Nginx 反向代理该服务(如监听localhost:3000),不能直接用 Nginx serveout/目录 - 若使用
output: 'export'(纯静态导出),则无需 Node 后端,但会失去 SSR/API 路由能力;此时 Nginx 只需静态托管out/,且必须配置try_files $uri $uri/ /index.html;支持客户端路由 - 默认(无 output 配置)即混合模式:SSG 页面走静态,
/api和 SSR 页面走 Node server —— 这是最常见也最需 Nginx 精确分流的场景
Nginx 配置核心:精准分流静态资源、API 和客户端路由
以下是一个生产就绪的 server 块示例(假设 Next.js dev/prod server 运行在 localhost:3000):
server {
listen 80;
server_name your-domain.com;
<h1>1. 优先匹配 _next/static 和 favicon.ico 等静态资源 → 直接由 Nginx 提供</h1><p>location ^~ /_next/static/ {
alias /var/www/your-app/.next/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /favicon.ico {
alias /var/www/your-app/public/favicon.ico;
}</p><h1>2. 匹配 /api/ → 全部反向代理到 Next.js 后端(关键!)</h1><p>location ^~ /api/ {
proxy_pass <a href="https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4">https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4</a>;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}</p><h1>3. 其他所有请求(包括 /、/about、/posts/123)→ 交由 Next.js 处理(支持 SSR + 客户端路由 fallback)</h1><p>location / {
proxy_pass <a href="https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4">https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4</a>;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}</p>
⚠️ 注意:^~ /api/ 必须写在 location / 之前,否则会被通配规则提前捕获,导致 API 请求被当作页面请求处理,引发 hydration mismatch。
验证与调试 hydration mismatch 的真实来源
不要只看控制台报错,按顺序排查:
- 打开浏览器开发者工具 → Network 标签页 → 刷新页面 → 查看所有
/api/xxx请求的响应状态和内容。如果返回的是 HTML(比如 200 +...),说明 Nginx 没有把它们代理给 Next.js 后端,而是错误地返回了首页(典型原因:location 顺序错或正则误配) - 对比服务端渲染的 HTML(curl https://www.php.cn/link/8e5687e2d6ab87e5da2f833f3e8986a4/)和浏览器实际加载的 HTML(右键 → 查看页面源代码),检查
<div id="__next"> 内容是否一致。不一致往往源于数据获取时机不同(如 <code>getServerSideProps依赖 header 或 cookie,而 Nginx 未透传) - 确认
next.config.js中assetPrefix未被错误设置(如设为"https://cdn.example.com"但 CDN 未同步最新/_next/文件) - 确保 Next.js 应用使用
Link组件跳转,而非原生<a href></a>;服务端对非 Link 跳转不会预渲染目标页,客户端 hydration 时可能拿不到预期 DOM 结构 - 若使用自定义
App.getInitialProps或getServerSideProps,检查是否依赖了仅在浏览器可用的 API(如window.location),这类代码必须加typeof window !== 'undefined'保护 - 升级到 Next.js 最新版,旧版本(如 12.x 早期)存在已知的
useEffect与服务端初始 state 不同步 bug,升级常可直接解决
额外加固项:避免常见陷阱
不推荐 在 Nginx 中重写 URL(如 rewrite ^/blog/(.*)$ /posts/$1 break;)来模拟 Next.js 路由——这会破坏服务端路由匹配逻辑,直接导致 hydration 失败。










