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

Next.js Serverless函数异常:Vercel部署后需手动触发后续请求

WhatsApp Webhook部署Vercel后异步请求失效问题解决

问题背景

我有一个接收WhatsApp Webhook消息的端点,逻辑是先异步调用另一个内部端点,再向WhatsApp返回200状态码。本地运行一切正常,但部署到Vercel后,只有第一个端点能触发,后续的内部请求必须手动Ping对应的端点才会执行。尝试加日志但Vercel生产环境调试困难,效果不好。相关代码如下:

const conversation = await prisma.conversation.findFirst({
          where: {
            senderId: message.senderId,
          },
        });
        console.log(
          `${process.env.BASE_URL}/api/whatsapp/services/preValidation`
        );

        if (!conversation?.verify || !conversation) {
          console.log("member is not verified yet");
          axios.post(
            `${process.env.BASE_URL}/api/whatsapp/services/preValidation`,
            {
              conversation: conversation,
              message: message,
              recipientId: teamId,
              source: "whatsapp",
            }
          );
          return new Response("message is not verified yet", {
            status: 200,
          });
        }

        axios.post(
          `${process.env.BASE_URL}/api/facebook/services/handleMessages`,
          {
            conversation: conversation,
            message: message,
            recipientId: teamId,
          }
        );
return new Response("EVENT_RECEIVED", { status: 200 });

核心原因

  1. Vercel无服务器函数进程终止机制:当函数返回响应后,Vercel会立刻终止进程,未完成的异步操作会被强制中断。当前代码里axios.post是异步执行的,但没等它完成就直接返回了200,导致后续请求还没来得及跑就被砍了。
  2. 函数冷启动休眠:Vercel的函数长时间没调用会进入休眠状态,首次调用需要冷启动。异步请求触发时,目标函数可能还在休眠,导致请求无法执行,手动Ping相当于唤醒函数完成冷启动。

解决方案

方案1:等待异步请求完成后再返回响应

给axios.post加上await,确保请求执行完再返回200。同时要设置超时时间,避免WhatsApp Webhook因为超时重复推送消息,还要捕获错误避免进程崩溃。

修改后代码:

const conversation = await prisma.conversation.findFirst({
  where: {
    senderId: message.senderId,
  },
});
console.log(`${process.env.BASE_URL}/api/whatsapp/services/preValidation`);

if (!conversation?.verify || !conversation) {
  console.log("member is not verified yet");
  try {
    // 等待请求完成,设置10秒超时适配WhatsApp Webhook限制
    await axios.post(
      `${process.env.BASE_URL}/api/whatsapp/services/preValidation`,
      {
        conversation: conversation,
        message: message,
        recipientId: teamId,
        source: "whatsapp",
      },
      { timeout: 10000 }
    );
  } catch (error) {
    console.error("preValidation请求失败:", error);
    // 即使请求失败,也要返回200给WhatsApp,防止重复推送
  }
  return new Response("message is not verified yet", { status: 200 });
}

try {
  await axios.post(
    `${process.env.BASE_URL}/api/facebook/services/handleMessages`,
    {
      conversation: conversation,
      message: message,
      recipientId: teamId,
    },
    { timeout: 10000 }
  );
} catch (error) {
  console.error("handleMessages请求失败:", error);
}
return new Response("EVENT_RECEIVED", { status: 200 });

方案2:用Vercel Queue处理后台异步任务

如果异步请求执行时间较长(超过15秒),超过WhatsApp Webhook的超时限制,就用Vercel Queue把任务放到后台执行。主函数立即返回200,保证WhatsApp不会重试,同时后台任务能正常跑完。

步骤1:定义队列任务

创建队列处理路由app/api/queues/process-message/route.ts:

import { Queue } from "@vercel/queue";
import axios from "axios";

const queue = new Queue("process-message");

export async function POST(request: Request) {
  const { type, payload } = await request.json();
  try {
    if (type === "preValidation") {
      await axios.post(
        `${process.env.BASE_URL}/api/whatsapp/services/preValidation`,
        payload
      );
    } else if (type === "handleMessages") {
      await axios.post(
        `${process.env.BASE_URL}/api/facebook/services/handleMessages`,
        payload
      );
    }
  } catch (error) {
    console.error("队列任务执行失败:", error);
    throw error; // 触发自动重试
  }
  return new Response("任务执行完成", { status: 200 });
}

步骤2:修改Webhook端点加入队列

const conversation = await prisma.conversation.findFirst({
  where: {
    senderId: message.senderId,
  },
});
console.log(`${process.env.BASE_URL}/api/whatsapp/services/preValidation`);

if (!conversation?.verify || !conversation) {
  console.log("member is not verified yet");
  // 将任务加入队列
  await fetch(`${process.env.BASE_URL}/api/queues/process-message`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      type: "preValidation",
      payload: {
        conversation: conversation,
        message: message,
        recipientId: teamId,
        source: "whatsapp",
      },
    }),
  });
  return new Response("message is not verified yet", { status: 200 });
}

await fetch(`${process.env.BASE_URL}/api/queues/process-message`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    type: "handleMessages",
    payload: {
      conversation: conversation,
      message: message,
      recipientId: teamId,
    },
  }),
});
return new Response("EVENT_RECEIVED", { status: 200 });

方案3:优化冷启动问题

  • 如果你是Vercel Pro计划用户,可以开启函数预热,设置最小实例数,避免函数休眠。
  • 将频繁调用的内部端点合并,减少冷启动触发次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:07:11