rewrites
重写允许你将传入请求路径映射到不同的目标路径。
¥Rewrites allow you to map an incoming request path to a different destination path.
重写充当 URL 代理并屏蔽目标路径,使用户看起来没有更改其在网站上的位置。相反,redirects 将重新路由到新页面并显示 URL 更改。
¥Rewrites act as a URL proxy and mask the destination path, making it appear the user hasn't changed their location on the site. In contrast, redirects will reroute to a new page and show the URL changes.
要使用重写,你可以在 next.config.js
中使用 rewrites
键:
¥To use rewrites you can use the rewrites
key in next.config.js
:
module.exports = {
async rewrites() {
return [
{
source: '/about',
destination: '/',
},
]
},
}
重写应用于客户端路由,<Link href="/about">
将在上面的示例中应用重写。
¥Rewrites are applied to client-side routing, a <Link href="/about">
will have the rewrite applied in the above example.
rewrites
是一个异步函数,它期望返回一个数组或一个数组对象(见下文),其中包含具有 source
和 destination
属性的对象:
¥rewrites
is an async function that expects to return either an array or an object of arrays (see below) holding objects with source
and destination
properties:
-
source
:String
- 是传入请求路径模式。¥
source
:String
- is the incoming request path pattern. -
destination
:String
是你要路由到的路径。¥
destination
:String
is the path you want to route to. -
basePath
:false
或undefined
- 如果为 false,则匹配时不会包含 basePath,只能用于外部重写。¥
basePath
:false
orundefined
- if false the basePath won't be included when matching, can be used for external rewrites only. -
locale
:false
或undefined
- 匹配时是否不应包含区域设置。¥
locale
:false
orundefined
- whether the locale should not be included when matching. -
has
是具有type
、key
和value
属性的 有对象 的数组。¥
has
is an array of has objects with thetype
,key
andvalue
properties. -
missing
是具有type
、key
和value
属性的 丢失对象 的数组。¥
missing
is an array of missing objects with thetype
,key
andvalue
properties.
当 rewrites
函数返回数组时,会在检查文件系统(页面和 /public
文件)之后、动态路由之前应用重写。当 rewrites
函数返回具有特定形状的数组对象时,可以更改此行为并进行更精细的控制,从 Next.js 的 v10.1
开始:
¥When the rewrites
function returns an array, rewrites are applied after checking the filesystem (pages and /public
files) and before dynamic routes. When the rewrites
function returns an object of arrays with a specific shape, this behavior can be changed and more finely controlled, as of v10.1
of Next.js:
module.exports = {
async rewrites() {
return {
beforeFiles: [
// These rewrites are checked after headers/redirects
// and before all files including _next/public files which
// allows overriding page files
{
source: '/some-page',
destination: '/somewhere-else',
has: [{ type: 'query', key: 'overrideMe' }],
},
],
afterFiles: [
// These rewrites are checked after pages/public files
// are checked but before dynamic routes
{
source: '/non-existent',
destination: '/somewhere-else',
},
],
fallback: [
// These rewrites are checked after both pages/public files
// and dynamic routes are checked
{
source: '/:path*',
destination: `https://my-old-site.com/:path*`,
},
],
}
},
}
很高兴知道:
beforeFiles
中的重写在匹配源后不会立即检查文件系统/动态路由,它们会继续,直到检查完所有beforeFiles
。¥Good to know: rewrites in
beforeFiles
do not check the filesystem/dynamic routes immediately after matching a source, they continue until allbeforeFiles
have been checked.
Next.js 路由的检查顺序是:
¥The order Next.js routes are checked is:
-
检查/应用 headers
¥headers are checked/applied
-
检查/应用 redirects
¥redirects are checked/applied
-
检查/应用
beforeFiles
重写¥
beforeFiles
rewrites are checked/applied -
检查/提供来自 公共目录、
_next/static
文件和非动态页面的静态文件¥static files from the public directory,
_next/static
files, and non-dynamic pages are checked/served -
检查/应用
afterFiles
重写,如果这些重写之一匹配,我们会在每次匹配后检查动态路由/静态文件¥
afterFiles
rewrites are checked/applied, if one of these rewrites is matched we check dynamic routes/static files after each match -
检查/应用
fallback
重写,这些重写在渲染 404 页面之前以及在检查动态路由/所有静态资源之后应用。如果你在getStaticPaths
中使用 倒退:true/'blocking',则next.config.js
中定义的后备rewrites
将不会运行。¥
fallback
rewrites are checked/applied, these are applied before rendering the 404 page and after dynamic routes/all static assets have been checked. If you use fallback: true/'blocking' ingetStaticPaths
, the fallbackrewrites
defined in yournext.config.js
will not be run.
重写参数
¥Rewrite parameters
在重写中使用参数时,如果 destination
.txt 中未使用任何参数,则默认情况下将在查询中传递参数。
¥When using parameters in a rewrite the parameters will be passed in the query by default when none of the parameters are used in the destination
.
module.exports = {
async rewrites() {
return [
{
source: '/old-about/:path*',
destination: '/about', // The :path parameter isn't used here so will be automatically passed in the query
},
]
},
}
如果在目标中使用参数,则不会在查询中自动传递任何参数。
¥If a parameter is used in the destination none of the parameters will be automatically passed in the query.
module.exports = {
async rewrites() {
return [
{
source: '/docs/:path*',
destination: '/:path*', // The :path parameter is used here so will not be automatically passed in the query
},
]
},
}
如果已通过在 destination
.txt 中指定查询在目标中使用参数,你仍然可以在查询中手动传递参数。
¥You can still pass the parameters manually in the query if one is already used in the destination by specifying the query in the destination
.
module.exports = {
async rewrites() {
return [
{
source: '/:first/:second',
destination: '/:first?second=:second',
// Since the :first parameter is used in the destination the :second parameter
// will not automatically be added in the query although we can manually add it
// as shown above
},
]
},
}
很高兴知道:来自重写的 自动静态优化 或 prerendering 参数的静态页面将在水合作用后在客户端上进行解析并在查询中提供。
¥Good to know: Static pages from Automatic Static Optimization or prerendering params from rewrites will be parsed on the client after hydration and provided in the query.
路径匹配
¥Path Matching
允许路径匹配,例如 /blog/:slug
将匹配 /blog/hello-world
(无嵌套路径):
¥Path matches are allowed, for example /blog/:slug
will match /blog/hello-world
(no nested paths):
module.exports = {
async rewrites() {
return [
{
source: '/blog/:slug',
destination: '/news/:slug', // Matched parameters can be used in the destination
},
]
},
}
通配符路径匹配
¥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 rewrites() {
return [
{
source: '/blog/:slug*',
destination: '/news/:slug*', // Matched parameters can be used in the destination
},
]
},
}
正则表达式路径匹配
¥Regex Path Matching
要匹配正则表达式路径,你可以将正则表达式括在参数后面的括号中,例如 /blog/:slug(\\d{1,})
将匹配 /blog/123
但不匹配 /blog/abc
:
¥To match a regex path you can wrap the regex in parenthesis after a parameter, for example /blog/:slug(\\d{1,})
will match /blog/123
but not /blog/abc
:
module.exports = {
async rewrites() {
return [
{
source: '/old-blog/:post(\\d{1,})',
destination: '/blog/:post', // Matched parameters can be used in the destination
},
]
},
}
以下字符 (
、)
、{
、}
、[
、]
、|
、\
、^
、.
、:
、*
、+
、-
、?
、$
用于正则表达式路径匹配,因此在 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 rewrites() {
return [
{
// this will match `/english(default)/something` being requested
source: '/english\\(default\\)/:slug',
destination: '/en-us/:slug',
},
]
},
}
标头、Cookie 和查询匹配
¥Header, Cookie, and Query Matching
仅当标头、cookie 或查询值也与 has
字段匹配或与 missing
字段不匹配时才匹配重写。source
和所有 has
项都必须匹配,并且所有 missing
项必须不匹配才能应用重写。
¥To only match a rewrite 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 rewrite to be applied.
has
和 missing
项目可以具有以下字段:
¥has
and missing
items can have the following fields:
-
type
:String
- 必须是header
、cookie
、host
或query
。¥
type
:String
- must be eitherheader
,cookie
,host
, orquery
. -
key
:String
- 所选类型中要匹配的键。¥
key
:String
- the key from the selected type to match against. -
value
:String
或undefined
- 要检查的值,如果未定义,则任何值都会匹配。类似正则表达式的字符串可用于捕获值的特定部分,例如 如果值first-(?<paramName>.*)
用于first-second
,则second
将可在目标中与:paramName
一起使用。¥
value
:String
orundefined
- 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 valuefirst-(?<paramName>.*)
is used forfirst-second
thensecond
will be usable in the destination with:paramName
.
module.exports = {
async rewrites() {
return [
// if the header `x-rewrite-me` is present,
// this rewrite will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// if the header `x-rewrite-me` is not present,
// this rewrite will be applied
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-rewrite-me',
},
],
destination: '/another-page',
},
// if the source, query, and cookie are matched,
// this rewrite 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',
},
],
destination: '/:path*/home',
},
// if the header `x-authorized` is present and
// contains a matching value, this rewrite will be applied
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
destination: '/home?authorized=:authorized',
},
// if the host is `example.com`,
// this rewrite will be applied
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
destination: '/another-page',
},
]
},
}
重写到外部 URL
¥Rewriting to an external URL
重写允许你重写到外部 url。这对于逐步采用 Next.js 特别有用。以下是将主应用的 /blog
路由重定向到外部站点的重写示例。
¥Rewrites allow you to rewrite to an external url. This is especially useful for incrementally adopting Next.js. The following is an example rewrite for redirecting the /blog
route of your main app to an external site.
module.exports = {
async rewrites() {
return [
{
source: '/blog',
destination: 'https://example.com/blog',
},
{
source: '/blog/:slug',
destination: 'https://example.com/blog/:slug', // Matched parameters can be used in the destination
},
]
},
}
如果你使用的是 trailingSlash: true
,则还需要在 source
参数中插入尾部斜杠。如果目标服务器也需要尾部斜杠,则它也应该包含在 destination
参数中。
¥If you're using trailingSlash: true
, you also need to insert a trailing slash in the source
parameter. If the destination server is also expecting a trailing slash it should be included in the destination
parameter as well.
module.exports = {
trailingSlash: true,
async rewrites() {
return [
{
source: '/blog/',
destination: 'https://example.com/blog/',
},
{
source: '/blog/:path*/',
destination: 'https://example.com/blog/:path*/',
},
]
},
}
Next.js 的逐步采用
¥Incremental adoption of Next.js
在检查所有 Next.js 路由后,你还可以让 Next.js 回退到代理到现有网站。
¥You can also have Next.js fall back to proxying to an existing website after checking all Next.js routes.
这样,你在将更多页面迁移到 Next.js 时无需更改重写配置
¥This way you don't have to change the rewrites configuration when migrating more pages to Next.js
module.exports = {
async rewrites() {
return {
fallback: [
{
source: '/:path*',
destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
},
],
}
},
}
使用 basePath 支持重写
¥Rewrites with basePath support
当利用 basePath
支持 进行重写时,每个 source
和 destination
都会自动添加 basePath
前缀,除非你将 basePath: false
添加到重写中:
¥When leveraging basePath
support with rewrites each source
and destination
is automatically prefixed with the basePath
unless you add basePath: false
to the rewrite:
module.exports = {
basePath: '/docs',
async rewrites() {
return [
{
source: '/with-basePath', // automatically becomes /docs/with-basePath
destination: '/another', // automatically becomes /docs/another
},
{
// does not add /docs to /without-basePath since basePath: false is set
// Note: this can not be used for internal rewrites e.g. `destination: '/another'`
source: '/without-basePath',
destination: 'https://example.com',
basePath: false,
},
]
},
}
重写并支持 i18n
¥Rewrites with i18n support
当利用 i18n
支持 进行重写时,每个 source
和 destination
都会自动添加前缀以处理配置的 locales
,除非你将 locale: false
添加到重写中。如果使用 locale: false
,则必须在 source
和 destination
前面加上区域设置前缀,才能正确匹配。
¥When leveraging i18n
support with rewrites each source
and destination
is automatically prefixed to handle the configured locales
unless you add locale: false
to the rewrite. 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 rewrites() {
return [
{
source: '/with-locale', // automatically handles all locales
destination: '/another', // automatically passes the locale on
},
{
// does not handle locales automatically since locale: false is set
source: '/nl/with-locale-manual',
destination: '/nl/another',
locale: false,
},
{
// this matches '/' since `en` is the defaultLocale
source: '/en',
destination: '/en/another',
locale: false,
},
{
// it's possible to match all locales even when locale: false is set
source: '/:locale/api-alias/:path*',
destination: '/api/:path*',
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',
},
]
},
}
版本历史
¥Version History
版本 | 变化 |
---|---|
v13.3.0 | 添加了 missing 。 |
v10.2.0 | 添加了 has 。 |
v9.5.0 | 添加了标题。 |