NextJS中如何无需封装API调用即可记录API请求耗时?
解决Next.js中间件统计API请求总耗时的方案
你当前的代码无法统计API真实耗时,是因为NextResponse.next()会立即返回,不会等待后端API处理完成,所以计算的只是中间件内部的处理时间,不是从请求进入到API响应返回的总耗时。
下面提供两种无需逐个封装API的解决方案:
方案一:代理API请求(推荐)
通过中间件拦截所有API路由请求,手动发起fetch调用实际API端点,等待响应返回后计算耗时。这种方式能准确获取完整的请求-响应周期时间,且无需修改任何API内部代码。
import { NextResponse } from 'next/server'; export default async function middleware(request) { // 仅处理/api开头的路由,可根据实际路由规则调整 if (request.nextUrl.pathname.startsWith('/api/')) { const startTime = Date.now(); // 原样转发请求到实际API,确保请求头、方法、请求体等参数一致 const apiResponse = await fetch(request.url, { headers: request.headers, method: request.method, body: request.body, credentials: 'same-origin', }); const endTime = Date.now(); const duration = endTime - startTime; console.log(`API ${request.nextUrl.pathname} 请求耗时: ${duration}ms`); // 返回克隆的响应对象,避免原响应流被消耗后无法使用 return new NextResponse(apiResponse.body, { status: apiResponse.status, statusText: apiResponse.statusText, headers: apiResponse.headers, }); } // 非API路由直接放行 return NextResponse.next(); } // 配置中间件仅匹配API路由,减少不必要的拦截 export const config = { matcher: '/api/:path*', };
方案二:监听响应流完成
利用响应体的可读流特性,通过克隆并读取整个响应流,等待流读取完成后计算耗时。这种方式不需要重新发起请求,但需要处理流的异步读取逻辑。
import { NextResponse } from 'next/server'; export default async function middleware(request) { if (request.nextUrl.pathname.startsWith('/api/')) { const startTime = Date.now(); const response = NextResponse.next(); // 仅当响应存在body时处理 if (response.body) { // 克隆响应体,避免原响应的流被消耗导致前端无法获取数据 const clonedBody = response.body.clone(); // 读取整个流直到结束 await new Promise(resolve => { const reader = clonedBody.getReader(); const readChunk = () => { reader.read().then(({ done }) => { done ? resolve() : readChunk(); }); }; readChunk(); }); const endTime = Date.now(); const duration = endTime - startTime; console.log(`API ${request.nextUrl.pathname} 请求耗时: ${duration}ms`); } return response; } return NextResponse.next(); } export const config = { matcher: '/api/:path*', };
两种方案对比
- 方案一:逻辑直观,耗时统计准确,适用于所有API场景;但需要手动转发请求参数,要注意处理特殊请求(如文件上传、自定义请求头)。
- 方案二:无需重新发起请求,性能开销更低;但仅适用于有响应体的API请求,对分块传输的大响应可能会有延迟统计的情况。
内容的提问来源于stack exchange,提问作者No Idea For Name
相关产品推荐
相关产品推荐

