Skip to main content

redirects

重定向允许你将传入请求路径重定向到不同的目标路径。

¥Redirects allow you to redirect an incoming request path to a different destination path.

要使用重定向,你可以在 next.config.js 中使用 redirects 键:

¥To use redirects you can use the redirects key in next.config.js:

module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
]
},
}

redirects 是一个异步函数,它期望返回一个包含具有 sourcedestinationpermanent 属性的对象的数组:

¥redirects is an async function that expects an array to be returned holding objects with source, destination, and permanent properties:

  • source 是传入请求路径模式。

    ¥source is the incoming request path pattern.

  • destination 是你要路由到的路径。

    ¥destination is the path you want to route to.

  • permanent truefalse - 如果 true 将使用 308 状态代码,指示客户端/搜索引擎永久缓存重定向,如果 false 将使用 307 状态代码,该状态代码是临时且不缓存的。

    ¥permanent true or false - if true will use the 308 status code which instructs clients/search engines to cache the redirect forever, if false will use the 307 status code which is temporary and is not cached.

为什么 Next.js 使用 307 和 308?传统上 302 用于临时重定向,301 用于永久重定向,但许多浏览器将重定向的请求方法更改为 GET,而不管原来的方法如何。例如,如果浏览器向 POST /v1/users 发出请求,该请求返回位置为 /v2/users 的状态代码 302,则后续请求可能是 GET /v2/users,而不是预期的 POST /v2/users。Next.js 使用 307 临时重定向和 308 永久重定向状态代码来显式保留所使用的请求方法。

¥Why does Next.js use 307 and 308? Traditionally a 302 was used for a temporary redirect, and a 301 for a permanent redirect, but many browsers changed the request method of the redirect to GET, regardless of the original method. For example, if the browser made a request to POST /v1/users which returned status code 302 with location /v2/users, the subsequent request might be GET /v2/users instead of the expected POST /v2/users. Next.js uses the 307 temporary redirect, and 308 permanent redirect status codes to explicitly preserve the request method used.

  • basePathfalseundefined - 如果为 false,则匹配时不会包含 basePath,只能用于外部重定向。

    ¥basePath: false or undefined - if false the basePath won't be included when matching, can be used for external redirects only.

  • localefalseundefined - 匹配时是否不应包含区域设置。

    ¥locale: false or undefined - whether the locale should not be included when matching.

  • has 是具有 typekeyvalue 属性的 有对象 的数组。

    ¥has is an array of has objects with the type, key and value properties.

  • missing 是具有 typekeyvalue 属性的 丢失对象 的数组。

    ¥missing is an array of missing objects with the type, key and value properties.

在包含页面和 /public 文件的文件系统之前检查重定向。

¥Redirects are checked before the filesystem which includes pages and /public files.

使用页面路由时,重定向不会应用于客户端路由(Linkrouter.push),除非 中间件 存在且与路径匹配。

¥When using the Pages Router, redirects are not applied to client-side routing (Link, router.push) unless Middleware is present and matches the path.

应用重定向时,请求中提供的任何查询值都将传递到重定向目标。例如,请参阅以下重定向配置:

¥When a redirect is applied, any query values provided in the request will be passed through to the redirect destination. For example, see the following redirect configuration:

{
source: '/old-blog/:path*',
destination: '/blog/:path*',
permanent: false
}

当请求 /old-blog/post-1?hello=world 时,客户端将被重定向到 /blog/post-1?hello=world

¥When /old-blog/post-1?hello=world is requested, the client will be redirected to /blog/post-1?hello=world.

路径匹配

¥Path Matching

允许路径匹配,例如 /old-blog/:slug 将匹配 /old-blog/hello-world(无嵌套路径):

¥Path matches are allowed, for example /old-blog/:slug will match /old-blog/hello-world (no nested paths):

module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}

通配符路径匹配

¥Wildcard Path Matching

要匹配通配符路径,你可以在参数后使用 *,例如 /blog/:slug* 将匹配 /blog/a/b/c/d/hello-world

¥To match a wildcard path you can use * after a parameter, for example /blog/:slug* will match /blog/a/b/c/d/hello-world:

module.exports = {
async redirects() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Matched parameters can be used in the destination
permanent: true,
},
]
},
}

正则表达式路径匹配

¥Regex Path Matching

要匹配正则表达式路径,你可以将正则表达式括在参数后面的括号中,例如 /post/:slug(\\d{1,}) 将匹配 /post/123 但不匹配 /post/abc

¥To match a regex path you can wrap the regex in parentheses after a parameter, for example /post/:slug(\\d{1,}) will match /post/123 but not /post/abc:

module.exports = {
async redirects() {
return [
{
source: '/post/:slug(\\d{1,})',
destination: '/news/:slug', // Matched parameters can be used in the destination
permanent: false,
},
]
},
}

以下字符 (){}:*+? 用于正则表达式路径匹配,因此当在 source 中用作非特殊值时,必须通过在其前面添加 \\ 来转义它们:

¥The following characters (, ), {, }, :, *, +, ? are used for regex path matching, so when used in the source as non-special values they must be escaped by adding \\ before them:

module.exports = {
async redirects() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
permanent: false,
},
]
},
}

¥Header, Cookie, and Query Matching

仅当标头、cookie 或查询值也与 has 字段匹配或与 missing 字段不匹配时才匹配重定向。source 和所有 has 项目都必须匹配,并且所有 missing 项目不得匹配才能应用重定向。

¥To only match a redirect when header, cookie, or query values also match the has field or don't match the missing field can be used. Both the source and all has items must match and all missing items must not match for the redirect to be applied.

hasmissing 项目可以具有以下字段:

¥has and missing items can have the following fields:

  • typeString - 必须是 headercookiehostquery

    ¥type: String - must be either header, cookie, host, or query.

  • keyString - 所选类型中要匹配的键。

    ¥key: String - the key from the selected type to match against.

  • valueStringundefined - 要检查的值,如果未定义,则任何值都会匹配。类似正则表达式的字符串可用于捕获值的特定部分,例如 如果值 first-(?<paramName>.*) 用于 first-second,则 second 将可在目标中与 :paramName 一起使用。

    ¥value: String or undefined - the value to check for, if undefined any value will match. A regex like string can be used to capture a specific part of the value, e.g. if the value first-(?<paramName>.*) is used for first-second then second will be usable in the destination with :paramName.

module.exports = {
async redirects() {
return [
// if the header `x-redirect-me` is present,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'header',
key: 'x-redirect-me',
},
],
permanent: false,
destination: '/another-page',
},
// if the header `x-dont-redirect` is present,
// this redirect will NOT be applied
{
source: '/:path((?!another-page$).*)',
missing: [
{
type: 'header',
key: 'x-do-not-redirect',
},
],
permanent: false,
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this redirect will be applied
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// the page value will not be available in the
// destination since value is provided and doesn't
// use a named capture group e.g. (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
permanent: false,
destination: '/another/:path*',
},
// if the header `x-authorized` is present and
// contains a matching value, this redirect will be applied
{
source: '/',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
permanent: false,
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this redirect will be applied
{
source: '/:path((?!another-page$).*)',
has: [
{
type: 'host',
value: 'example.com',
},
],
permanent: false,
destination: '/another-page',
},
]
},
}

通过 basePath 支持进行重定向

¥Redirects with basePath support

当利用 basePath 支持 进行重定向时,每个 sourcedestination 都会自动添加 basePath 前缀,除非你将 basePath: false 添加到重定向中:

¥When leveraging basePath support with redirects each source and destination is automatically prefixed with the basePath unless you add basePath: false to the redirect:

module.exports = {
basePath: '/docs',

async redirects() {
return [
{
source: '/with-basePath', // automatically becomes /docs/with-basePath
destination: '/another', // automatically becomes /docs/another
permanent: false,
},
{
// does not add /docs since basePath: false is set
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
permanent: false,
},
]
},
}

支持 i18n 的重定向

¥Redirects with i18n support

当利用 i18n 支持 进行重定向时,每个 sourcedestination 都会自动添加前缀以处理配置的 locales,除非你将 locale: false 添加到重定向。如果使用 locale: false,则必须在 sourcedestination 前面加上区域设置前缀,才能正确匹配。

¥When leveraging i18n support with redirects each source and destination is automatically prefixed to handle the configured locales unless you add locale: false to the redirect. If locale: false is used you must prefix the source and destination with a locale for it to be matched correctly.

module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},

async redirects() {
return [
{
source: '/with-locale', // automatically handles all locales
destination: '/another', // automatically passes the locale on
permanent: false,
},
{
// does not handle locales automatically since locale: false is set
source: '/nl/with-locale-manual',
destination: '/nl/another',
locale: false,
permanent: false,
},
{
// this matches '/' since `en` is the defaultLocale
source: '/en',
destination: '/en/another',
locale: false,
permanent: false,
},
// it's possible to match all locales even when locale: false is set
{
source: '/:locale/page',
destination: '/en/newpage',
permanent: false,
locale: false,
},
{
// this gets converted to /(en|fr|de)/(.*) so will not match the top-level
// `/` or `/fr` routes like /:path* would
source: '/(.*)',
destination: '/another',
permanent: false,
},
]
},
}

在极少数情况下,你可能需要为旧的 HTTP 客户端分配自定义状态代码才能正确重定向。在这些情况下,你可以使用 statusCode 属性而不是 permanent 属性,但不能同时使用两者。为了确保 IE11 兼容性,会自动为 308 状态码添加 Refresh 标头。

¥In some rare cases, you might need to assign a custom status code for older HTTP Clients to properly redirect. In these cases, you can use the statusCode property instead of the permanent property, but not both. To to ensure IE11 compatibility, a Refresh header is automatically added for the 308 status code.

其他重定向

¥Other Redirects

版本历史

¥Version History

版本变化
v13.3.0添加了 missing
v10.2.0添加了 has
v9.5.0添加了 redirects