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}</>
}
import { after } from 'next/server'
// 自定义日志函数
import { log } from '@/app/utils'
export default function Layout({ children }) {
after(() => {
// 在布局渲染并发送给用户后执行
log()
})
return <>{children}</>
}
须知:
after
不是 动态 API (Dynamic API),调用它不会导致路由变为动态路由。如果在静态页面中使用,回调将在构建时或页面重新验证时执行。
参考
参数
- 一个回调函数,该函数将在响应(或预渲染)完成后执行。
执行时长
after
将运行至平台默认或您路由配置的 maxDuration
最大时长。如果您的平台支持,可以通过路由段配置设置超时限制。
须知
- 即使响应未成功完成,
after
也会执行。包括抛出错误或调用notFound
和redirect
的情况。 - 可以使用 React 的
cache
来对after
内部调用的函数进行去重。 after
可以嵌套在其他after
调用中,例如,您可以创建封装after
调用的工具函数以添加额外功能。
示例
与请求 API 结合使用
在 服务端操作 (Server Actions) 和 路由处理器 (Route Handlers) 中,可以在 after
内部使用请求 API,如 cookies
和 headers
。这对于在数据变更后记录用户活动非常有用。例如:
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' },
})
}
import { after } from 'next/server'
import { cookies, headers } from 'next/headers'
import { logUserAction } from '@/app/utils'
export async function POST(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.0 | after 成为稳定功能。 |
v15.0.0-rc | 引入 unstable_after 。 |