Redirecting 重定向
There are a few ways you can handle redirects in Next.js. This page will go through each available option, use cases, and how to manage large numbers of redirects.
在 Next.js 中,有几种方法可以处理重定向。此页面将介绍每个可用选项、用例以及如何管理大量重定向。
API | Purpose | Where | Status Code |
---|---|---|---|
| Redirect user after a mutation or event | Server Components, Server Actions, Route Handlers | 307 (Temporary) or 303 (Server Action) |
| Redirect user after a mutation or event | Server Components, Server Actions, Route Handlers | 308 (Permanent) 308(永久) |
| Perform a client-side navigation | Event Handlers in Client Components | N/A |
| Redirect an incoming request based on a path |
| 307 (Temporary) or 308 (Permanent) |
| Redirect an incoming request based on a condition | Middleware 中间件 | Any |
1.redirect function redirect 函数
The redirect function allows you to redirect the user to another URL. You can call redirect in Server Components, Route Handlers, and Server Actions.
使用 redirect 函数可以将用户重定向到另一个 URL。您可以在服务器组件、路由处理程序和服务器操作中调用 redirect 。
redirect is often used after a mutation or event. For example, creating a post:
redirect 通常在发生突变或事件后使用。例如,创建帖子:
'use server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function createPost(id: string) {
try {
// Call database
} catch (error) {
// Handle errors
}
revalidatePath('/posts') // Update cached posts
redirect(`/post/${id}`) // Navigate to the new post page
}
Good to know: 值得了解:
redirect
returns a 307 (Temporary Redirect) status code by default. When used in a Server Action, it returns a 303 (See Other), which is commonly used for redirecting to a success page as a result of a POST request.redirect
默认返回 307(临时重定向)状态代码。当在服务器操作中使用时,它返回 303(另请参阅),通常用于在 POST 请求的结果中重定向到成功页面。redirect
internally throws an error so it should be called outside oftry/catch
blocks.redirect
内部引发错误,因此应在try/catch
块之外调用它。redirect
can be called in Client Components during the rendering process but not in event handlers. You can use theuseRouter
hook instead.redirect
可以在渲染过程中在客户端组件中调用,但不能在事件处理程序中调用。您可以改用useRouter
钩子。redirect
also accepts absolute URLs and can be used to redirect to external links.redirect
也接受绝对 URL,可用于重定向到外部链接。If you'd like to redirect before the render process, use
next.config.js
or Middleware.
如果您想在渲染过程之前重定向,请使用next.config.js
或中间件。
2.permanentRedirect function permanentRedirect 函数
The permanentRedirect function allows you to permanently redirect the user to another URL. You can call permanentRedirect in Server Components, Route Handlers, and Server Actions.
使用 permanentRedirect 函数可以将用户永久重定向到另一个 URL。您可以在服务器组件、路由处理程序和服务器操作中调用 permanentRedirect 。
permanentRedirect is often used after a mutation or event that changes an entity's canonical URL, such as updating a user's profile URL after they change their username:
permanentRedirect 通常在更改实体的规范 URL 的突变或事件后使用,例如在用户更改其用户名后更新用户的个人资料 URL:
'use server'
import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'
export async function updateUsername(username: string, formData: FormData) {
try {
// Call database
} catch (error) {
// Handle errors
}
revalidateTag('username') // Update all references to the username
permanentRedirect(`/profile/${username}`) // Navigate to the new user profile
}
Good to know: 值得了解:
permanentRedirect
returns a 308 (permanent redirect) status code by default.permanentRedirect
默认返回 308(永久重定向)状态代码。permanentRedirect
also accepts absolute URLs and can be used to redirect to external links.permanentRedirect
也接受绝对 URL,可用于重定向到外部链接。If you'd like to redirect before the render process, use
next.config.js
or Middleware.
如果您想在渲染过程之前重定向,请使用next.config.js
或中间件。
3.useRouter() hook useRouter() 钩子
If you need to redirect inside an event handler in a Client Component, you can use the push
method from the useRouter
hook. For example:
如果您需要在客户端组件的事件处理程序中进行重定向,则可以使用 useRouter
钩子中的 push
方法。例如:
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
4.redirects in next.config.js redirects 在 next.config.js 中
The redirects option in the next.config.js file allows you to redirect an incoming request path to a different destination path. This is useful when you change the URL structure of pages or have a list of redirects that are known ahead of time.
redirects 选项在 next.config.js 文件中允许您将传入的请求路径重定向到不同的目标路径。当您更改页面的 URL 结构或提前知道重定向列表时,这非常有用。
redirects supports path, header, cookie, and query matching, giving you the flexibility to redirect users based on an incoming request.
redirects 支持路径、标头、Cookie 和查询匹配,让您可以根据传入的请求灵活地重定向用户。
To use redirects, add the option to your next.config.js file:
中使用 redirects ,请将选项添加到 next.config.js 文件:
module.exports = {
async redirects() {
return [
// Basic redirect
{
source: '/about',
destination: '/',
permanent: true,
},
// Wildcard path matching
{
source: '/blog/:slug',
destination: '/news/:slug',
permanent: true,
},
]
},
}
Good to know: 值得了解:
redirects
can return a 307 (Temporary Redirect) or 308 (Permanent Redirect) status code with thepermanent
option.redirects
可以使用permanent
选项返回 307(临时重定向)或 308(永久重定向)状态代码。redirects
may have a limit on platforms. For example, on Vercel, there's a limit of 1,024 redirects. To manage a large number of redirects (1000+), consider creating a custom solution using Middleware. See managing redirects at scale for more.redirects
在平台上可能有限制。例如,在 Vercel 上,重定向的限制为 1,024 个。要管理大量重定向(1000 个以上),请考虑使用中间件创建自定义解决方案。有关更多信息,请参阅大规模管理重定向。redirects
runs before Middleware.redirects
在中间件之前运行。
5.NextResponse.redirect in Middleware 中间件中的NextResponse.redirect
Middleware allows you to run code before a request is completed. Then, based on the incoming request, redirect to a different URL using NextResponse.redirect. This is useful if you want to redirect users based on a condition (e.g. authentication, session management, etc) or have a large number of redirects.
中间件允许您在请求完成之前运行代码。然后,根据传入的请求,使用 NextResponse.redirect 重定向到不同的 URL。如果您想根据条件(例如身份验证、会话管理等)重定向用户或有大量重定向,这将非常有用。
For example, to redirect the user to a /login page if they are not authenticated:
例如,如果用户未通过身份验证,则将其重定向到 /login 页面:
import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'
export function middleware(request: NextRequest) {
const isAuthenticated = authenticate(request)
// If the user is authenticated, continue as normal
if (isAuthenticated) {
return NextResponse.next()
}
// Redirect to login page if not authenticated
return NextResponse.redirect(new URL('/login', request.url))
}
export const config = {
matcher: '/dashboard/:path*',
}
Good to know: 值得了解:
Middleware runs after
redirects
innext.config.js
and before rendering.
中间件在next.config.js
中的redirects
之后和渲染之前运行。
6.Managing redirects at scale (advanced) 大规模管理重定向(高级)
To manage a large number of redirects (1000+), you may consider creating a custom solution using Middleware. This allows you to handle redirects programmatically without having to redeploy your application.
要管理大量重定向(1000 个以上),您可以考虑使用中间件创建自定义解决方案。这允许您以编程方式处理重定向,而无需重新部署应用程序。
To do this, you'll need to consider:
为此,您需要考虑:
Creating and storing a redirect map.
创建和存储重定向映射。
Optimizing data lookup performance.
优化数据查找性能。
a. Creating and storing a redirect map 创建和存储重定向映射
A redirect map is a list of redirects that you can store in a database (usually a key-value store) or JSON file.
重定向映射是您可以存储在数据库(通常是键值存储)或 JSON 文件中的重定向列表。
Consider the following data structure:
考虑以下数据结构:
{
"/old": {
"destination": "/new",
"permanent": true
},
"/blog/post-old": {
"destination": "/blog/post-new",
"permanent": true
}
}
In Middleware, you can read from a database such as Vercel's Edge Config or Redis, and redirect the user based on the incoming request:
在 Middleware 中,您可以从数据库(例如 Vercel 的 Edge Config 或 Redis)中读取,并根据传入的请求重定向用户:
import { NextResponse, NextRequest } from 'next/server'
import { get } from '@vercel/edge-config'
type RedirectEntry = {
destination: string
permanent: boolean
}
export async function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname
const redirectData = await get(pathname)
if (redirectData && typeof redirectData === 'string') {
const redirectEntry: RedirectEntry = JSON.parse(redirectData)
const statusCode = redirectEntry.permanent ? 308 : 307
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
// No redirect found, continue without redirecting
return NextResponse.next()
}
b.Optimizing data lookup performance 优化数据查找性能
Reading a large dataset for every incoming request can be slow and expensive. There are two ways you can optimize data lookup performance:
为每个传入请求读取大型数据集可能会很慢且昂贵。您可以通过两种方式优化数据查找性能:
-Use a database that is optimized for fast reads, such as Vercel Edge Config or Redis.
使用针对快速读取进行优化的数据库,例如 Vercel Edge Config 或 Redis。
-Use a data lookup strategy such as a Bloom filter to efficiently check if a redirect exists before reading the larger redirects file or database.
使用数据查找策略(例如布隆过滤器)在读取较大的重定向文件或数据库之前有效检查重定向是否存在。
Considering the previous example, you can import a generated bloom filter file into Middleware, then, check if the incoming request pathname exists in the bloom filter.
考虑到之前的示例,您可以将生成的布隆过滤器文件导入到中间件中,然后检查传入的请求路径名是否存在于布隆过滤器中。
If it does, forward the request to a Route Handler which will check the actual file and redirect the user to the appropriate URL. This avoids importing a large redirects file into Middleware, which can slow down every incoming request.
如果存在,则将请求转发到将检查实际文件并将用户重定向到适当 URL 的路由处理程序。这避免了将大型重定向文件导入到中间件中,这可能会减慢每个传入请求的速度。
import { NextResponse, NextRequest } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
// Initialize bloom filter from a generated JSON file
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any)
export async function middleware(request: NextRequest) {
// Get the path for the incoming request
const pathname = request.nextUrl.pathname
// Check if the path is in the bloom filter
if (bloomFilter.has(pathname)) {
// Forward the pathname to the Route Handler
const api = new URL(
`/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
request.nextUrl.origin
)
try {
// Fetch redirect data from the Route Handler
const redirectData = await fetch(api)
if (redirectData.ok) {
const redirectEntry: RedirectEntry | undefined =
await redirectData.json()
if (redirectEntry) {
// Determine the status code
const statusCode = redirectEntry.permanent ? 308 : 307
// Redirect to the destination
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
}
} catch (error) {
console.error(error)
}
}
// No redirect found, continue the request without redirecting
return NextResponse.next()
}
Then, in the Route Handler:
然后,在路由处理程序中:
import { NextRequest, NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
export function GET(request: NextRequest) {
const pathname = request.nextUrl.searchParams.get('pathname')
if (!pathname) {
return new Response('Bad Request', { status: 400 })
}
// Get the redirect entry from the redirects.json file
const redirect = (redirects as Record<string, RedirectEntry>)[pathname]
// Account for bloom filter false positives
if (!redirect) {
return new Response('No redirect', { status: 400 })
}
// Return the redirect entry
return NextResponse.json(redirect)
}
Good to know: 值得了解:
To generate a bloom filter, you can use a library like
bloom-filters
.
要生成布隆过滤器,您可以使用像bloom-filters
这样的库。You should validate requests made to your Route Handler to prevent malicious requests.
您应该验证对路由处理程序发出的请求,以防止恶意请求。