Vercel部署的NextJS端点调用WhatsApp API出现504超时错误
问题分析与解决方案
核心原因
你遇到的504超时问题,本质是WhatsApp Webhook的响应超时要求与当前代码同步处理逻辑的冲突:
- WhatsApp要求Webhook端点必须在10秒内返回响应,否则会重复发送请求;
- 你的代码在处理POST请求时,会先执行
generateResponse和调用Facebook API这两个异步操作,再返回200响应。如果这两个操作的总耗时接近或超过10秒,Vercel的Serverless Function会触发超时,同时WhatsApp会不断重试,导致大量504日志。
代码层面修复(优先解决)
1. 立即返回响应,异步处理消息逻辑
修改POST请求的处理流程,先给WhatsApp返回200确认,再后台异步处理回复操作:
import type { NextApiRequest, NextApiResponse } from 'next' import axios from 'axios' export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method === 'GET') { const mode = req.query['hub.mode'] const challenge = req.query['hub.challenge'] const token = req.query['hub.verify_token'] if (mode && token) { if (mode === 'subscribe' && token === myToken) { res.status(200).send(challenge) } else { // 修复:添加end()避免请求挂起 res.status(403).end() } } else { // 补充分支:无mode或token时返回403 res.status(403).end() } } else if (req.method === 'POST') { const body = req.body if (!secretKey) { return res.status(404).json({ message: 'No Secret Key Provided' }) } if (body.object && body.entry?.[0].changes?.[0].value.messages?.[0]) { // 先立即返回200,确认收到请求 res.status(200).end() // 异步处理消息回复,不阻塞响应 (async () => { try { const phoneId = body.entry[0].changes[0].value.metadata.phone_number_id const from = body.entry[0].changes[0].value.messages[0].from const msg_body = body.entry[0].changes[0].value.messages[0].text.body const response = await generateResponse(msg_body) await axios({ method: 'post', url: `https://graph.facebook.com/v17.0/${phoneId}/messages`, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}`, }, data: { messaging_product: 'whatsapp', to: from, text: { body: response }, }, }) } catch (err) { console.error('消息处理失败:', err) } })() } else { res.status(404).end() } } else { res.status(404).end() } }
2. 修复GET请求的遗漏分支
原GET请求中,当mode或token不存在时,没有返回响应,会导致请求挂起,引发超时。需要补充else分支返回403并结束请求。
3. 添加消息去重
WhatsApp会因超时重复发送相同消息,建议用Vercel KV或Redis存储已处理的消息ID,避免重复回复:
// 处理消息前检查是否已处理过 const msgId = body.entry[0].changes[0].value.messages[0].id const isProcessed = await kv.get(`processed:${msgId}`) if (isProcessed) return // 处理完成后标记已处理 await kv.set(`processed:${msgId}`, 'true', { ex: 86400 }) // 24小时过期
Vercel配置层面调整
1. 调整函数超时时间
Vercel Serverless Functions默认超时10秒,可在vercel.json中调整到最大60秒(但核心还是异步处理,因为WhatsApp只等10秒):
{ "functions": { "pages/api/your-endpoint.ts": { "maxDuration": 60 } } }
2. 使用Edge Functions
Edge Functions启动更快,超时时间30秒,适合处理Webhook。只需在函数顶部添加:
export const config = { runtime: 'edge', }
3. 检查环境变量
确保myToken、secretKey、accessToken等环境变量在Vercel控制台正确配置,没有未定义的情况导致代码异常。
内容的提问来源于stack exchange,提问作者Ben Shekhtman
相关产品推荐
相关产品推荐

