You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13 App Router API路由中非阻塞Fetch请求无法触发问题

Next.js 13(App Router)Vercel生产环境中非阻塞Fetch请求无法触发的问题解决

问题原因分析

  • Vercel的Serverless函数在执行完成(返回响应给客户端)后会立即终止进程,所有未完成的异步任务都会被直接中断。开发环境中Next.js的dev服务器不会立刻终止进程,因此未加await的请求能继续执行;但生产环境的Serverless函数没有等待异步任务完成的机制,导致未await的请求还没来得及发送就被销毁。
  • 你发起的axios.post属于“fire-and-forget”的异步操作,但函数执行到return true后就结束了,Vercel会立刻销毁该函数的运行环境,请求自然无法触发。

解决方案

1. 消息队列(推荐方案,彻底解决长任务超时问题)

这是处理长异步任务的标准做法,既能让用户立即收到响应,又能规避Vercel的5分钟函数超时限制,流程如下:

  • 主API路由拆分PDF后,将每个chunk的任务信息发送到消息队列;
  • 单独创建Serverless函数作为队列处理器,从队列中取出任务执行embedding生成逻辑;
  • 主路由直接返回响应告知用户任务已启动,用户可通过后续接口查询进度。

代码示例(以BullMQ为例)

首先安装依赖:

npm install bullmq

主函数修改:

import { Queue } from 'bullmq';

// 初始化队列,用Vercel KV作为Redis存储
const embeddingQueue = new Queue('embedding-generation', {
  connection: {
    host: process.env.KV_REST_API_URL,
    port: parseInt(process.env.KV_REST_API_PORT || '6379'),
    password: process.env.KV_REST_API_TOKEN,
  },
});

export default async function generateEmbeddingsForPDF(
    workspaceDataSource: WorkspaceFile, 
    supabase: SupabaseClient<Database, 'public'>,
    request: NextRequest
): Promise<boolean>
{
    const { data, error } = await supabase
    .storage.from('workspace-files')
    .download(workspaceDataSource.filePath);

    if (error && !data)
    {
        console.error('ERROR Downloading File::', error);
        return false;
    }

    try
    {
        const pdfLoader = new PDFLoader(data);
        const pageContentList = (await pdfLoader.loadAndSplit()).map(page => page.pageContent);
        const chunkSplitSize = 50;

        // 将所有chunk任务加入队列
        for (let i = 0; i < pageContentList.length; i += chunkSplitSize)
        {
            const chunks = pageContentList.slice(i, i + chunkSplitSize);
            await embeddingQueue.add('process-chunk', {
                workspaceFile: workspaceDataSource,
                textChunks: chunks,
                totalChunks: pageContentList.length,
                cookie: request.headers.get('cookie'),
            });
        }
    }
    catch (error)
    {
        console.error('Error splitting pdf into pages::', error);
        return false;
    }

    return true;
}

创建队列处理器(/app/api-v1/workspaces/generate-embeddings/processor/route.ts):

import { Worker } from 'bullmq';
import axios from 'axios';

// 初始化任务处理器
const worker = new Worker('embedding-generation', async (job) => {
  const { workspaceFile, textChunks, totalChunks, cookie } = job.data;
  const url = `${process.env.NEXT_PUBLIC_APP_URL}/api-v1/workspaces/generate-embeddings/ingestor`;
  
  await axios.post(url, {
    workspaceFile,
    textChunks,
    totalChunks,
  }, {
    headers: {
      cookie,
      'Content-Type': 'application/json',
    }
  });
}, {
  connection: {
    host: process.env.KV_REST_API_URL,
    port: parseInt(process.env.KV_REST_API_PORT || '6379'),
    password: process.env.KV_REST_API_TOKEN,
  },
});

// 监听任务失败事件
worker.on('failed', (job, err) => {
  console.error(`Job ${job.id} failed: ${err.message}`);
});

// 路由仅用于初始化Worker
export async function GET() {
  return new Response('Worker running', { status: 200 });
}

2. 临时方案:强制等待请求发送(不适合长任务)

如果暂时不想引入队列,可以用Promise.allSettled收集所有请求的Promise并等待,确保请求至少被发送出去,但主函数会等待所有请求启动后才返回,仍受Vercel超时限制,仅适合短任务:

// 替换原for循环部分
const requests = [];
for (let i = 0; i < pageContentList.length; i += chunkSplitSize)
{
    const chunks = pageContentList.slice(i, i + chunkSplitSize);
    const url = `${request.nextUrl.origin}/api-v1/workspaces/generate-embeddings/ingestor`;
    
    const reqPromise = axios.post(url, {
        workspaceFile: workspaceDataSource,
        textChunks: chunks,
        totalChunks: pageContentList.length,
    }, {
        headers: {
            cookie: request.headers.get('cookie'),
            'Content-Type': 'application/json',
        }
    }).catch(err => {
        console.error('ERROR WITH EMBEDDINGS DISPATCHER::', err);
    });
    requests.push(reqPromise);
}
// 等待所有请求完成发送(不一定执行完毕)
await Promise.allSettled(requests);

内容的提问来源于stack exchange,提问作者Angus Moore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:30:02