Next.js 14 App Router如何实现301重定向?
问题
我的项目里产品的slug支持动态更新,当slug更新后,我希望旧slug的页面能以301永久重定向跳转到新slug页面,但目前只能实现308重定向。我已经尝试过以下两种方案,都没达到预期:
- 在Page组件中使用
permanentRedirect:
export default async function Page({ params: { slug } }: Props) { const productData: Promise<Product> = getProduct(slug); const product = await productData; if (product.slug !== slug) { // redirect to the correct slug permanentRedirect(`/product/${product.slug}`); } // 其他页面逻辑 }
- 在
next.config.js中配置静态redirects:
async redirects() { return [ { source: '/product/old-slug-example', destination: '/product/new-slug', permanent: true, }, ]; },
另外我也试过客户端重定向,同样没用。我必须用301的核心原因是SEO,业内普遍认为308无法满足SEO需求,必须用301重定向。
解决方案
方案一:手动指定301状态码的redirect函数
Next.js的permanentRedirect封装的是308重定向,如果需要强制返回301,可以直接使用底层的redirect函数,手动传入301状态码:
import { redirect } from 'next/navigation'; export default async function Page({ params: { slug } }: Props) { const product = await getProduct(slug); if (product.slug !== slug) { // 手动指定301状态码实现永久重定向 redirect(`/product/${product.slug}`, 301); } // 其他页面渲染逻辑 }
注意:在App Router中,redirect的第二个参数如果传'permanent',部分环境下仍会返回308,直接传数字301可以确保返回正确的状态码。
方案二:用Middleware处理动态全局重定向
如果产品slug是动态更新的,无法提前在next.config.js中配置所有旧slug,推荐使用Next.js Middleware在请求层面处理重定向,这是最灵活的方案:
创建项目根目录的middleware.ts(或.js)文件:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export async function middleware(request: NextRequest) { const { pathname } = request.nextUrl; // 匹配/product/[slug]格式的路径 const slugMatch = pathname.match(/^\/product\/([^\/]+)$/); if (slugMatch) { const requestedSlug = slugMatch[1]; // 根据请求的slug获取产品数据,替换成你实际的产品查询逻辑 const product = await getProduct(requestedSlug); // 如果产品存在且slug不匹配,返回301重定向 if (product && product.slug !== requestedSlug) { const newUrl = new URL(`/product/${product.slug}`, request.url); return NextResponse.redirect(newUrl, { status: 301 }); } } // 正常请求继续执行 return NextResponse.next(); } // 指定Middleware只匹配产品页面路径 export const config = { matcher: '/product/:slug*', };
这个方案的优势是能自动处理所有动态生成的旧slug,不需要手动维护重定向规则,且直接在服务器端返回301状态码,完全满足SEO的需求。
补充说明
Next.js默认用308替代301是因为308会保留原始请求方法(比如POST),但搜索引擎对301的支持更成熟。如果必须使用301,上述两种方案都能解决问题,其中Middleware更适合动态更新的场景。
内容的提问来源于stack exchange,提问作者ilyas
相关产品推荐
相关产品推荐

