after

after 允许您在响应(或预渲染)完成后调度执行任务。这对于不应阻塞响应的操作和其他副作用(如日志记录和分析)非常有用。

该函数可用于服务端组件 (Server Components)(包括 generateMetadata)、服务端操作 (Server Actions)路由处理器 (Route Handlers)中间件 (Middleware)

该函数接受一个回调函数,该回调将在响应(或预渲染)完成后执行:

import { after } from 'next/server'
// 自定义日志函数
import { log } from '@/app/utils'

export default function Layout({ children }: { children: React.ReactNode }) {
  after(() => {
    // 在布局渲染并发送给用户后执行
    log()
  })
  return <>{children}</>
}

须知: after 不是 动态 API (Dynamic API),调用它不会导致路由变为动态路由。如果在静态页面中使用,回调将在构建时或页面重新验证时执行。

参考

参数

  • 一个回调函数,该函数将在响应(或预渲染)完成后执行。

执行时长

after 将运行至平台默认或您路由配置的 maxDuration 最大时长。如果您的平台支持,可以通过路由段配置设置超时限制。

须知

  • 即使响应未成功完成,after 也会执行。包括抛出错误或调用 notFoundredirect 的情况。
  • 可以使用 React 的 cache 来对 after 内部调用的函数进行去重。
  • after 可以嵌套在其他 after 调用中,例如,您可以创建封装 after 调用的工具函数以添加额外功能。

示例

与请求 API 结合使用

服务端操作 (Server Actions)路由处理器 (Route Handlers) 中,可以在 after 内部使用请求 API,如 cookiesheaders。这对于在数据变更后记录用户活动非常有用。例如:

import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'

export async function POST(request: Request) {
  // 执行数据变更
  // ...

  // 记录用户活动用于分析
  after(async () => {
    const userAgent = (await headers().get('user-agent')) || 'unknown'
    const sessionCookie =
      (await cookies().get('session-id'))?.value || 'anonymous'

    logUserAction({ sessionCookie, userAgent })
  })

  return new Response(JSON.stringify({ status: 'success' }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
  })
}

但是,不能在 服务端组件 (Server Components)after 中使用这些请求 API。这是因为 Next.js 需要知道树的哪些部分访问了请求 API 以支持 部分预渲染 (Partial Prerendering),而 after 在 React 的渲染生命周期之后运行。

平台支持

部署方式是否支持
Node.js 服务器
Docker 容器
静态导出
适配器视平台而定

了解如何配置 after 当自托管 Next.js 时。

参考:在无服务器平台支持 after 在无服务器环境中使用 after 需要等待异步任务在响应发送后完成。在 Next.js 和 Vercel 中,这是通过名为 waitUntil(promise) 的原语实现的,它会延长无服务器调用的生命周期,直到传递给 waitUntil 的所有 Promise 都完成。

如果您希望用户能够使用 after,您需要提供行为类似的 waitUntil 实现。

当调用 after 时,Next.js 会像这样访问 waitUntil

const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = contextValue?.waitUntil

这意味着 globalThis[Symbol.for('@next/request-context')] 需要包含如下对象:

type NextRequestContext = {
  get(): NextRequestContextValue | undefined
}

type NextRequestContextValue = {
  waitUntil?: (promise: Promise<any>) => void
}

以下是一个实现示例:

import { AsyncLocalStorage } from 'node:async_hooks'

const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()

// 定义并注入 Next.js 将使用的访问器
const RequestContext: NextRequestContext = {
  get() {
    return RequestContextStorage.getStore()
  },
}
globalThis[Symbol.for('@next/request-context')] = RequestContext

const handler = (req, res) => {
  const contextValue = { waitUntil: YOUR_WAITUNTIL }
  // 提供上下文值
  return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}

版本历史

版本历史描述
v15.1.0after 成为稳定功能。
v15.0.0-rc引入 unstable_after

On this page