404页面生效取决于服务器返回404状态码和text/html响应头;GitHub Pages需根目录404.html且路径为/404.html;Netlify/Vercel/Express需显式配置404状态码;静态资源须内联,链接用绝对路径。

404页面是否生效,不取决于你写了什么HTML,而取决于服务器是否返回了 404 状态码和 text/html 响应头。本地双击打开 404.html 永远不会触发真正的404——那只是个普通200页面。
GitHub Pages 必须用 /404.html 路径
GitHub Pages 只识别根目录下名为 404.html 的文件,且必须能通过 /404.html 这个确切路径访问(不能是 /error/404.html)。它不会执行 JavaScript 路由逻辑,所以如果你用 React/Vue 的 history 模式,得额外在 404.html 里加回退脚本:
<script>
if (window.location.pathname !== '/404.html') {
window.location.href = '/';
}
</script>- 文件名大小写敏感:必须是
404.html,不是404.HTML或NotFound.html - 提交后需等待几分钟,GitHub 缓存可能延迟生效
- 无法覆盖默认行为:比如把
/api/*排除在外,所有未命中路径都走这个页面
Netlify 需显式声明 404 状态码
Netlify 默认会渲染 404.html,但若不配置重定向规则,它可能返回 200 状态——这会让 SEO 抓取失败。正确做法是在项目根目录建 _redirects 文件:
/* /404.html 404
或在 netlify.toml 中写:
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
[[redirects]] from = "/*" to = "/404.html" status = 404
- 仅靠放一个
404.html不够,必须用重定向规则强制返回 404 状态 -
_redirects文件不能有扩展名,也不能放在子目录 - 该规则优先级高于其他路由,包括已存在的静态文件(如
/favicon.ico)
纯静态 HTML 页面禁止外部资源请求
404 页面本身可能因路径错误被加载,比如用户访问 /assets/main.css 失败,浏览器再尝试加载 /404.html;如果这个页面又引用了 /css/style.css,就会触发第二次404,造成白屏或样式丢失。
- 所有 CSS 必须用
<style></style>内联,字体用系统栈:font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif - 图标用内联 SVG 或 data URI,禁用
<img src="icon.svg"> - JavaScript 仅用于简单跳转(如
history.back()),不调用fetch、localStorage等可能失败的 API - 避免
<meta http-equiv="refresh">:它返回 200 状态,且对屏幕阅读器不友好
Vercel 和自建 Node.js 服务要手动设状态
Vercel 默认不识别 404.html,必须在 vercel.json 中配置重写并确保状态码正确:
{
"rewrites": [{ "source": "/(.*)", "destination": "/404.html" }]
}⚠️ 这种写法实际返回的是 200——你需要改用 routes 或部署时启用 notFound: true(Next.js 场景)。Express 用户则必须显式设置:
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, '404.html'));
});- 顺序很重要:这个中间件必须放在所有路由之后,否则会拦截正常请求
- 别用
res.redirect(404, '/404.html'):3xx 状态码会跳转,不是真正的 404 - 测试时别用
npx serve -s:它默认 fallback 到index.html,要用npx serve(无-s)才能看到真实404
最容易被忽略的一点:404页面里的链接,比如“返回首页”,必须指向绝对路径 /,而不是相对路径 ./index.html——后者在深层路径(如 /blog/post/xxx)下会拼成错误地址。


















