使用 Node.js 收发 WhatsApp 消息
接收是一个响应 Meta 验证 GET 请求并接受 POST 请求的路由。发送是一次 fetch 调用,通过号码的 phone number id 和访问令牌向 Cloud API 发出请求。我们没有提供 SDK,也没有需要安装的东西。
用于 Meta 验证的 GET 请求,以及用于事件的 POST 请求。
客户发送消息后,可以发送自由文本的时间窗口。
在该时间窗口外发送自由文本时返回的错误。
如何在 Node 中接收消息?
在 Express、Fastify、Next 路由处理程序或普通服务器中,使用一个包含两种方法的路由。
GET 请求负责回应 Meta 的验证:从查询中读取 hub.mode、hub.verify_token 和 hub.challenge,将令牌与您的令牌比较,然后以纯文本返回 challenge。以 JSON 返回是最常见的错误,会产生一个看似正确却永远收不到任何内容的端点。
POST 请求接收事件。立即响应 200,之后再处理。Meta 会重试任何处理缓慢的请求,而在响应前完成工作的处理程序会看到同一条消息不止一次。尤其在无服务器环境中,先返回响应,再将工作放入队列,才能避免冷启动变成重复处理。
如何发送消息?
向该 phone number id 对应的 Cloud API messages 端点发出 fetch 请求,并在 bearer 标头中携带访问令牌。
这部分没有任何内容是我们专有的,因此请求与 Meta 自己的文档完全一致,不需要学习或受制于任何包装层。两个值都在控制台中;如果由助手完成接入,MCP 连接器的 get_api_credentials 会返回它们。
请求正文取决于时间。在客户最后一条入站消息后的 24 小时内,发送 text 对象。超过该时间后,发送包含已批准模板名称和语言的 template 对象。只会发送文本的代码可以通过所有测试,却会在第一条夜间到达的消息上失败。
无服务器环境有什么不同?
有两点,而且都与函数在工作完成前结束有关。
响应 200 后继续处理,无法在函数一响应就冻结的平台上正常运行。请使用平台提供的机制让响应后仍能继续工作,或将负载推入队列,再由另一个函数处理。Meta 只需要快速收到确认,不需要工作已经完成。
冷启动也会让响应变慢,从而导致更多重试和重复消息。在这种架构中,按 wamid 消息 id 去重不是可选项,而是保证可靠性的关键。
常见错误
- 将 challenge 以 JSON 返回,而不是作为原始正文返回。
- 在响应 200 前处理工作。无服务器环境中,函数可能在响应的瞬间冻结。
- 跳过去重。Meta 的设计就是会重试,重复消息很常见,不是边缘情况。
在 easycoexistence.com 连接号码,将 Webhook 目的地设为您的路由,然后从控制台读取 phone number id 和访问令牌。每个号码每月 US$ 9 起,量大时降至 US$ 2,前 7 天免费。
常见问题
我需要使用库吗?
不需要。一个路由和 fetch 就足够,而且调用与 Meta 的文档完全一致。
这能在 Vercel 或 Lambda 上运行吗?
可以,但要注意常见的无服务器限制:先确认收到请求,再通过队列或后台机制处理,而不是在请求内联处理。
如何验证请求确实来自 Meta?
使用您的 app secret 检查签名标头。端点公开后,应尽快完成这项验证。
我可以使用 TypeScript 吗?
可以。我们没有需要您进行类型定义的内容,因为负载属于 Meta,且由 Meta 提供文档说明。
继续阅读
准备开始了吗?
几分钟即可设置 WhatsApp Coexistence,而不是几个月。应用会继续在手机上运行。
开始免费试用验证时间