Next.js 部署后刷新页面 404
Next.js 部署后刷新页面 404:原因与终极解决方案
你是否遇到过这样的场景:在本地开发时 Next.js 应用路由一切正常,但部署到服务器后,手动刷新页面或直接访问某个子路由时,却返回了冰冷的 404 错误?这篇教程将带你从根源上理解问题,并提供针对不同部署环境的一站式解决方案,即使你是后端基础较弱的初学者也能轻松上手。
一、问题复现:刷新为什么会 404?
假设你的 Next.js 应用有两个页面:
/(首页)/about(关于页)
本地使用 next dev 启动时,访问 http://localhost:3000/about 不会出错。
但部署到生产环境后,在浏览器中 直接输入域名/about 或 在/about页面按F5刷新,就会出现 404。
究其原因,这与 Next.js 的路由机制 以及 部署环境如何处理请求 密切相关。
二、核心原因:客户端路由与服务器端文件查找的冲突
Next.js 是一个混合框架,支持两种渲染模式:
- 静态生成(Static Generation):在构建时即生成 HTML 文件。
- 服务端渲染(SSR)或增量静态再生成(ISR):请求到来时动态生成页面。
当你使用 <Link href="/about"> 进行导航时,Next.js 会拦截点击事件,通过浏览器的 History API 在前端进行路由切换,根本不会向服务器发起完整的页面请求。页面内容由 JavaScript 动态替换,所以一切正常。
但当你刷新页面或直接访问 /about 时,浏览器会向服务器发送一个真实的 HTTP 请求(例如 GET /about)。此时:
- 如果
/about页面是纯静态生成(next build && next export或单独生成):服务器上必须存在about.html这个物理文件。Nginx、Apache 这类传统静态服务器是根据 URL 路径去文件系统查找对应文件的,如果找不到,就会返回 404。 - 如果使用 Node.js 服务器或 Serverless 平台(如 Vercel):服务器默认能正确将所有请求指向
next start处理,它们会自动将/about映射到 Next.js 的pages/about.js,然后决定渲染 SSR 还是返回静态文件。因此一般不会有问题。
核心矛盾:
Next.js 是单页应用(SPA)风格的框架,但它的“页面”并不完全是实际存在的静态文件。传统静态服务器的“文件名匹配”逻辑无法理解前端路由结构。
三、不同部署方案的“对症下药”
下面根据你实际选择的部署方式,给出最直接的修复方案。请对号入座。
3.1 使用 Vercel / Netlify(推荐零配置方案)
如果你将项目部署到 Vercel(Next.js 官方平台),默认自带完美的路由处理,无需任何额外配置,所有子路由都能正常刷新。
这就是为什么很多教程说“部署到 Vercel 就解决了”——因为它内置了对 next build 的完整支持。
Netlify 也提供了类似的 Next.js 适配插件。
建议在项目根目录创建 netlify.toml,使用 Next.js 的必要构建插件:
[build]
command = "npm run build"
publish = "out" # 如果你使用 next export,填out;若使用serverless插件则按插件说明
[[plugins]]
package = "@netlify/plugin-nextjs"
部署后刷新即可正常运行。
3.2 使用静态导出(next export)部署到任意静态服务器
如果你必须使用 next export 生成纯静态 HTML 文件(类似于 Gatsby 的构建方式),那么:
- 导出命令:
npx next build && npx next export - 输出目录通常是
out/
此时每一个页面都会被生成为对应的 HTML 文件,例如 about.html。
但你直接访问 /about 时,服务器需要知道 about 对应 about.html。因此必须配置 URL 重写规则,让服务器自动补全 .html 后缀或将所有未知路径回退到 index.html(后者更适合 SPA 模式,但 Next.js 静态导出通常保留真实路径)。
Nginx 示例(补全 .html 后缀):
server {
listen 80;
server_name example.com;
root /var/www/out;
location / {
# 尝试直接访问URI,不存在则尝试加上.html后缀
try_files $uri $uri.html $uri/ =404;
}
}
Apache 示例(.htaccess 文件):
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^(.+?)/?$ $1.html [L]
配置后,访问 /about 会返回 about.html 的内容。
注意:如果你的页面中有动态路由(例如 [id].js),静态导出会将数据预渲染到对应的 HTML 中,但刷新时路径结构必须符合导出规则。
3.3 使用 Nginx 反向代理 Node.js 服务器(next start)
很多自建服务器用户喜欢用 Nginx 做反向代理,将请求转发给本地运行的 next start。这种情况下,Nginx 必须将所有无法匹配的请求(或所有请求)都交给 Node.js 处理,否则仍会 404。
标准配置如下:
server {
listen 80;
server_name your-domain.com;
location /_next/static {
alias /path/to/your/.next/static;
expires 365d;
}
location / {
proxy_pass http://localhost:3000; # next start 运行的端口
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
关键的 location / 块会将除静态资源外的流量全数转发给 Next.js。这样刷新任何页面都不会 404。
3.4 使用 Docker 或直接运行 next start(无 Nginx)
如果你的应用直接通过 npm run start(即 next start)对外服务,并且没有前置反向代理,则刷新页面通常不会 404。因为 Next.js 的生产服务器本身就能正确处理所有路由。
但请确保:构建和启动命令正确。
- 构建:
npx next build(生成.next文件夹) - 启动:
npx next start(读取.next并启动服务器)
只要你没有删除 .next 目录,直接访问子路由就无忧。
3.5 使用云服务(阿里云 OSS / AWS S3)托管静态导出文件
在对象存储类服务中托管静态网站,需要配置错误文档(索引文档)处理或重定向规则。
以 AWS S3 为例:
- 开启静态网站托管。
- 索引文档设置为
index.html。 - 错误文档也设置为
index.html(适用于 SPA 回退,但会将全部 404 回退到首页,可能影响 SEO)。 - 更好的方式是:使用 CloudFront 添加 自定义错误响应,当 HTTP 404 时,响应路径改为
/index.html,状态码改为 200。
阿里云 OSS:
在控制台设置 默认首页 为 index.html,默认 404 页 同样指向 index.html(SPA 方案),或者更精细地设置 CDN 回源规则,对不同路径进行重写。
⚠️ 注意:如果大量使用回退至 index.html,虽然解决了刷新 404,但会丢失原始 URL 信息,不利于 SEO,推荐仅在无奈情况下使用。
四、进阶:使用 Hash 路由(不推荐,但可行)
如果你完全无法控制服务器配置(例如一些老旧的主机),并且使用的是纯静态导出,可以考虑将 Next.js 的链接改为 Hash 路由。
但这需要舍弃 Next.js 原生基于路径的路由,引入第三方库(如 react-router 的 HashRouter),与 Next.js 的文件系统路由体系冲突,迁移成本极高, 不推荐作为常规方案。仅在极其受限的环境中考虑。
一个更简单的“折中”是:所有页面作为单页面应用(SPA)模式,通过一个 index.html 承载,配合 next/router,但同样需要改动较大,且失去 SEO 优势。
五、总结:你的 404 解决路线图
| 你的部署方式 | 最快解决方案 |
|---|---|
| Vercel / Netlify | 无需任何操作,默认支持。 |
| 静态导出 + Nginx/Apache | 配置 try_files 或 .htaccess 重写。 |
| Nginx 反向代理 next start | 将 / 下的请求全部 proxy_pass 到 Node。 |
| 直接运行 next start | 确保正确执行 build 和 start。 |
| 对象存储(OSS/S3) | 设置错误文档回退至 index.html 或重写。 |
根本原则:部署环境必须理解 “每个路由都可以回退给 Next.js 处理”,无论是通过服务器重定向还是反向代理。一旦你理解了这个本质,所有平台的配置都变得异曲同工。
现在,对照你的部署方案,操练起来吧!只需几分钟的配置,即可让刷新 404 永远消失。