Node.js实现WhatsApp云API Webhook会话超时及手机号存储问题
问题分析与修复方案
你的代码无法正确存储手机号主要源于几个关键错误,以下是针对性的修复步骤:
核心问题点
- 会话存储变量名不一致:定义的是
const session = {},但后续代码全用复数sessions,导致会话数据根本没存在正确的存储对象里。 - 手机号提取路径错误:中间件里直接取
req.body.phoneNumber,但WhatsApp Webhook的用户手机号实际嵌套在req.body.entry[0].changes[0].value.messages[0].from路径下。 - 缺少JSON解析中间件:Express默认不会自动解析POST请求的JSON Body,导致
req.body为空,无法提取任何有效数据。 - UUID模块重复加载:每次生成Session ID时都重新require模块,既低效又不符合Node.js模块加载规范。
修复后的完整代码
const express = require('express'); const uuid = require('uuid'); // 提前导入UUID模块,避免重复加载 const app = express(); // 必须添加JSON解析中间件,放在所有路由之前 app.use(express.json()); // 统一会话存储变量名 const sessions = {}; function sessionMiddleware(sessionTimeout) { return function(req, res, next) { // 正确从WhatsApp Webhook Payload中提取用户手机号,添加可选链避免报错 let phoneNumber = null; if (req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]) { phoneNumber = req.body.entry[0].changes[0].value.messages[0].from; } // 未获取到手机号时(如Webhook验证请求、非消息类事件),直接跳过会话处理 if (!phoneNumber) { req.session = null; return next(); } // 根据手机号查找已有会话ID const sessionId = getSessionIdFromPhoneNumber(phoneNumber); if (sessionId && sessions[sessionId]) { const session = sessions[sessionId]; const currentTime = new Date().getTime(); if (currentTime - session.lastAccessTime > sessionTimeout) { // 会话超时,删除会话 delete sessions[sessionId]; req.session = null; } else { // 更新会话最后访问时间 session.lastAccessTime = currentTime; req.session = session.data; } } else { // 创建新会话 const newSessionId = generateSessionId(); const currentTime = new Date().getTime(); const newSession = { sessionId: newSessionId, creationTime: currentTime, lastAccessTime: currentTime, phoneNumber: phoneNumber, data: {} }; sessions[newSessionId] = newSession; req.session = newSession.data; } next(); } } function getSessionIdFromPhoneNumber(phoneNumber) { // 简化遍历逻辑 for (const sessionId of Object.keys(sessions)) { const session = sessions[sessionId]; if (session.phoneNumber === phoneNumber) { return sessionId; } } return null; } function generateSessionId() { return uuid.v4(); } app.post("/webhook", sessionMiddleware(30 * 60 * 1000), (req, res) => { const phone_number_id = req.body.entry[0].changes[0].value.metadata.phone_number_id; const from = req.body.entry[0].changes[0].value.messages[0].from; // 这里添加你的业务逻辑处理代码 // 必须返回200状态码给WhatsApp,否则会重复触发Webhook res.status(200).send("OK"); }); // 启动服务器 const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
额外注意事项
- 必须给WhatsApp Webhook返回200状态码,否则Meta会判定服务不可用,重复发送请求。
- 可添加非消息事件的处理逻辑(如状态更新),避免无效的会话创建。
- 生产环境建议用Redis等持久化存储替代内存中的
sessions对象,防止服务器重启后会话丢失。
内容的提问来源于stack exchange,提问作者Dendy Tiawan Putra
相关产品推荐
相关产品推荐

