redirect

redirect 函數允許您將使用者重新導向至另一個 URL。redirect 可用於伺服器組件 (Server Components)路由處理器 (Route Handlers)伺服器操作 (Server Actions)

串流上下文 (streaming context)中使用時,會插入一個 meta 標籤以在客戶端觸發重新導向。在伺服器操作中使用時,會向呼叫方返回 303 HTTP 重新導向回應。其他情況下則會返回 307 HTTP 重新導向回應。

如果資源不存在,您可以使用 notFound 函數替代。

參考

參數

redirect 函數接受兩個參數:

redirect(path, type)
參數類型描述
pathstring要重新導向的 URL,可以是相對或絕對路徑。
type'replace' (預設) 或 'push' (在 Server Actions 中預設)重新導向的類型。

預設情況下,redirect伺服器操作 (Server Actions) 中會使用 push(在瀏覽器歷史堆疊中添加新項目),在其他地方則使用 replace(替換瀏覽器歷史堆疊中的當前 URL)。您可以通過指定 type 參數來覆蓋此行為。

type 參數在伺服器組件中使用時無效。

返回值

redirect 不返回任何值。

行為

  • 在伺服器操作和路由處理器中,redirect 應在 try/catch 區塊之後呼叫。
  • 如果您希望返回 308 (永久) HTTP 重新導向而非 307 (臨時),可以使用 permanentRedirect 函數
  • redirect 內部會拋出錯誤,因此應在 try/catch 區塊外呼叫。
  • redirect 可以在客戶端組件的渲染過程中使用,但不能在事件處理程序中使用。您可以使用 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')
  }

  // ...
}

須知redirect 不需要使用 return redirect(),因為它使用了 TypeScript 的 never 類型。

客戶端組件

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