404页面应返回真实404状态码并渲染自定义HTML,而非301/302重定向;仅SPA在GitHub Pages等静态托管场景下可利用404.html做前端路由兜底。

404 页面不该重定向(尤其是 301/302),而应返回真实 404 状态码 + 自定义 HTML 内容;只有单页应用(SPA)等特殊场景才需用 404.html 做前端路由兜底。
为什么不能对 404 做 301/302 重定向
这是最常踩的坑:把所有 404 请求用 301 强制跳首页,看似“友好”,实则破坏 HTTP 语义和 SEO:
-
301表示“资源已永久迁移”,但用户访问的 /nonexistent 并没迁移到 /,它就是不存在 —— 服务器返回301会让搜索引擎误认为该 URL 与首页内容等价,稀释首页权重 - 日志里再也看不到真实的 404 请求路径,无法发现死链、拼写错误或爬虫试探
- 浏览器地址栏会跳变,SPA 用户刷新深层路由(如
/dashboard/settings)时,本该由前端路由接管,却被重定向打断体验
nginx 中正确配置自定义 404 页面
目标是:返回真实 404 状态码,同时展示你写的 404.html —— 不是跳转,而是“渲染”。
- 确保
fastcgi_intercept_errors on;已启用(在http或server块内),否则error_page不生效 - 在
server块中添加:error_page 404 /404.html;(路径必须以/开头,且/404.html需存在于网站根目录) - 确认你的
404.html文件第一行包含<html><head><title>404 Not Found</title></head>等基础结构,避免被某些 CDN 或代理截断 - 测试方式:访问一个明显不存在的路径(如
/this-path-does-not-exist),用浏览器开发者工具 Network 面板检查响应状态码是否为404,而非200或301
GitHub Pages 部署 SPA 时的 404.html 特殊用法
这是唯一合理使用 404.html 做“重定向”的场景:利用 GitHub Pages 的 404 响应机制,让前端路由接管所有路径。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
立即学习“前端免费学习笔记(深入)”;
- 在项目根目录放一个
404.html,内容需包含一段 JS,读取window.location并用history.replaceState()或window.location.replace()把 URL 改写成带/?/xxx格式(例如/about→/?/about) - 关键点:这个 JS 必须在页面加载后立即执行,且不能依赖外部框架(因为此时 index.html 还没加载)
- 如果仓库是用户页(
username.github.io),pathSegmentsToKeep设为0;如果是项目页(username.github.io/repo),设为1,否则路径会被截断 - 注意:此方案仅适用于静态托管平台不支持
try_files的限制场景,非 SPA 请勿模仿
CodeIgniter 等 PHP 框架中的 404 路由控制
框架层的“404 处理”本质是捕获未匹配路由,不是 HTTP 重定向,而是调用指定控制器方法并返回 404 状态。
- 在
application/config/routes.php中设置:$route['404_override'] = 'errors/page404'; - 在
Errors控制器的page400()方法里,先手动发送状态:show_404();或http_response_code(404);,再$this->load->view('404'); - 切勿在该方法里写
redirect()或header("Location: ..."),否则状态码变成302 - 如果想对某类 URL(如旧博客链接)做 301,应单独写路由规则,而不是全局覆盖
404_override
真正难的不是写几行配置,而是分清“用户看到什么”和“服务器返回什么”——前者可以很友好,后者必须诚实。很多团队上线后才发现搜索流量下跌、死链堆积,根源都在 error_page 后忘了验证状态码,或把 404_override 当成了跳转开关。


















