vercel.json 中 redirect 须用 redirects 数组,source 必须带前导斜杠且按顺序匹配,文件存在时 redirect 被忽略;headers 不作用于 redirect 响应本身,仅对静态文件和函数生效,组合自定义 header 与跳转需用 rewrite + html 中转或 edge function。

vercel.json 里 redirect 的写法和常见失效原因
重定向在 vercel.json 中靠 redirects 数组实现,不是 rewrites,也不是 headers —— 混用会导致跳转不触发或返回 404。
典型写法:
{
"redirects": [
{
"source": "/old-page",
"destination": "/new-page",
"permanent": true
}
]
}
-
source是匹配路径,支持*(如/blog/:slug*),但不支持正则捕获组;需注意开头斜杠必须有,source: "old-page"不会匹配任何请求 -
destination可以是站内路径,也可以是完整 URL(如"https://example.com"),后者会自动设为 307(临时)跳转,加"permanent": true才变成 301 - 多个 redirect 会按数组顺序匹配,一旦命中就终止,所以更具体的规则要放在前面,比如
/blog/2023应该排在/blog/:slug*前面 - 如果页面实际存在(如
/old-page对应一个old-page.html),Vercel 默认优先服务文件,redirect 会被忽略——此时必须删掉对应文件,或改用rewrites+ 自定义 404 处理
通过 headers 配置自定义响应头的限制与实操
headers 字段只对静态文件(HTML、CSS、JS、图片等)和 Serverless 函数返回生效,对 redirect 响应本身无效——也就是说,你不能给 301 跳转响应加 Cache-Control 或 Cross-Origin-Embedder-Policy。
正确用法示例:
{
"headers": [
{
"source": "/(.*)\.(js|css|png|jpg|gif|svg)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
]
},
{
"source": "/index.html",
"headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Cross-Origin-Opener-Policy", "value": "same-origin" }
]
}
]
}
-
source支持 glob,但不支持正则表达式中的^或$;(.*)是唯一能匹配多级路径的方式 - 所有 header key 必须小写(Vercel 会标准化),但值大小写敏感;例如
"value": "same-origin"不能写成"Same-Origin" - 某些安全头(如
Cross-Origin-Embedder-Policy)要求配合Cross-Origin-Opener-Policy使用,单独设置可能被浏览器忽略 - 如果你用的是
app/目录或src/app(Next.js App Router),headers在vercel.json中对动态路由(如/dashboard)不生效,得改用generateStaticParams+export const runtime = 'edge'+NextResponse.next()注入
redirect 和 headers 组合使用的边界情况
想让某个跳转页带自定义 header?不行。Vercel 不允许在 redirect 响应中插入额外 header。唯一变通方式是:用 rewrites 指向一个中间 HTML 文件(如 redirector.html),再在这个文件里用 <meta http-equiv="refresh"> 或 JS 跳转,并通过 headers 规则给这个 HTML 文件加头。
- 例如:把
/legacy重定向到/new并带Referrer-Policy: no-referrer,就得建一个legacy.html,内容为<meta http-equiv="refresh" content="0; url=/new">,然后在headers中匹配/legacy.html加头 - 这种做法牺牲了 HTTP 状态码语义(返回 200 而非 301),SEO 效果弱,仅适合内部管理页或兼容旧链接
- 如果必须保留状态码且加 header,只能上 Edge Function,在
middleware.ts里用NextResponse.redirect()+.headers.set(),但这就脱离了vercel.json的声明式配置范畴
部署后验证 redirect 和 headers 是否生效
别只靠浏览器地址栏跳转成功就认为 OK。真实生效要看响应头和状态码。
- 用
curl -I https://yoursite.vercel.app/old-page查看是否返回301或307,以及location头是否正确 - 对静态资源运行
curl -I https://yoursite.vercel.app/style.css,确认cache-control等头是否存在且值准确 - Vercel 的日志里不会记录
vercel.json配置错误,只有构建失败或运行时异常;如果 redirect 没反应,先检查vercel.json是否在项目根目录、是否被.gitignore排除、是否语法合法(JSON 不支持注释) - 本地
vercel dev不完全模拟生产行为:它不处理redirects中的外部 URL 跳转,也不强制应用headers到所有匹配路径,务必上线后验证
最常被忽略的一点:Vercel 会缓存 301 重定向长达数小时,改完 vercel.json 后用隐身窗口或 curl -H "Cache-Control: no-cache" 测试,否则你以为没生效,其实是浏览器或 CDN 缓存住了旧规则。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











