redirect 重定向函数

redirect 函数允许你将用户重定向到另一个 URL。该函数可用于 服务端组件 (Server Components)路由处理器 (Route Handlers)服务端操作 (Server Actions)

流式上下文 (streaming context) 中使用时,会插入一个 meta 标签在客户端触发重定向。在服务端操作中使用时,会向调用方返回 303 HTTP 重定向响应。其他情况下会返回 307 HTTP 重定向响应。

如果资源不存在,可以使用 notFound 函数 替代。

参考文档

参数

redirect 函数接受两个参数:

redirect(path, type)
参数类型描述
pathstring要重定向到的 URL,可以是相对路径或绝对路径。
type'replace'(默认值)或 'push'(服务端操作中默认)指定重定向类型。

默认情况下,redirect服务端操作 (Server Actions) 中使用 push(在浏览器历史记录栈中添加新条目),其他情况下使用 replace(替换浏览器历史记录栈中的当前 URL)。可以通过指定 type 参数来覆盖此行为。

type 参数在服务端组件中使用时无效。

返回值

redirect 不返回任何值。

行为说明

  • 在服务端操作和路由处理器中,redirect 应在 try/catch 块之后调用。
  • 如果需要返回 308(永久)HTTP 重定向而非 307(临时),可以使用 permanentRedirect 函数
  • redirect 内部会抛出错误,因此应在 try/catch 块之外调用。
  • redirect 可以在客户端组件 (Client Components) 的渲染过程中调用,但不能在事件处理程序中调用。事件处理程序应使用 useRouter 钩子
  • redirect 也接受绝对 URL,可用于重定向到外部链接。
  • 如果需要在渲染过程之前重定向,可以使用 next.config.js中间件 (Middleware)

示例

服务端组件

调用 redirect() 函数会抛出 NEXT_REDIRECT 错误并终止所在路由段的渲染。

import { redirect } from 'next/navigation'

async function fetchTeam(id: string) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const team = await fetchTeam(id)

  if (!team) {
    redirect('/login')
  }

  // ...
}
import { redirect } from 'next/navigation'

async function fetchTeam(id) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }) {
  const { id } = await params
  const team = await fetchTeam(id)

  if (!team) {
    redirect('/login')
  }

  // ...
}

须知:由于使用了 TypeScript 的 never 类型,redirect 不需要使用 return redirect()

客户端组件

redirect 可以直接在客户端组件中使用。

'use client'

import { redirect, usePathname } from 'next/navigation'

export function ClientRedirect() {
  const pathname = usePathname()

  if (pathname.startsWith('/admin') && !pathname.includes('/login')) {
    redirect('/admin/login')
  }

  return <div>Login Page</div>
}
'use client'

import { redirect, usePathname } from 'next/navigation'

export function ClientRedirect() {
  const pathname = usePathname()

  if (pathname.startsWith('/admin') && !pathname.includes('/login')) {
    redirect('/admin/login')
  }

  return <div>Login Page</div>
}

须知:在服务端渲染 (SSR) 期间初始页面加载时,在客户端组件中使用 redirect 会执行服务端重定向。

可以通过服务端操作在客户端组件中使用 redirect。如果需要使用事件处理程序重定向用户,可以使用 useRouter 钩子。

'use client'

import { navigate } from './actions'

export function ClientRedirect() {
  return (
    <form action={navigate}>
      <input type="text" name="id" />
      <button>Submit</button>
    </form>
  )
}
'use client'

import { navigate } from './actions'

export function ClientRedirect() {
  return (
    <form action={navigate}>
      <input type="text" name="id" />
      <button>Submit</button>
    </form>
  )
}
'use server'

import { redirect } from 'next/navigation'

export async function navigate(data: FormData) {
  redirect(`/posts/${data.get('id')}`)
}
'use server'

import { redirect } from 'next/navigation'

export async function navigate(data) {
  redirect(`/posts/${data.get('id')}`)
}

常见问题

为什么 redirect 使用 307 和 308?

使用 redirect() 时,你可能会注意到临时重定向使用 307 状态码,永久重定向使用 308 状态码。传统上临时重定向使用 302,永久重定向使用 301,但许多浏览器在使用 302 时会将请求方法从 POST 改为 GET,而不管原始请求方法是什么。

以从 /users 重定向到 /people 为例,如果向 /users 发起 POST 请求创建新用户,并遵循 302 临时重定向,请求方法会从 POST 变为 GET。这并不合理,因为创建新用户应该向 /people 发起 POST 请求,而不是 GET 请求。

引入 307 状态码可以保持请求方法为 POST

  • 302 - 临时重定向,会将请求方法从 POST 改为 GET
  • 307 - 临时重定向,会保持请求方法为 POST

redirect() 方法默认使用 307 而非 302 临时重定向,意味着你的请求将始终保持为 POST 方法。

了解更多 关于 HTTP 重定向的信息。

版本历史

版本变更
v13.0.0引入 redirect 函数。