本地运行正常但Heroku部署失效的Facebook Messenger Bot问题
嘿,我来帮你分析下这个本地正常、部署到Heroku就失效的Messenger Bot问题~
可能的原因及对应解决方案
1. Heroku Dyno 休眠导致定时任务“失踪”
Heroku的免费/hobby级dyno有个特性:30分钟没收到请求就会自动休眠,休眠期间你的应用完全停止运行,node-schedule创建的定时任务自然没法执行。就算之后有新请求唤醒dyno,之前创建的定时任务也会因为应用重启而丢失。
解决办法:
- 如果需要定时任务持续运行,考虑升级到标准级dyno(不会休眠),或者改用Heroku官方的Scheduler插件——这是专门为Heroku场景设计的定时任务工具,它会定期唤醒dyno执行指定脚本,比
node-schedule更适配Heroku的环境。 - 要是暂时不想升级,也可以用外部定时服务定期给你的Heroku域名发请求保持dyno唤醒,但免费dyno每天有运行时长限制,这只能作为临时方案。
2. Webhook 配置或请求处理有遗漏
本地测试时你可能用了ngrok转发请求,但部署到Heroku后得确认这些点:
- Facebook开发者后台的Webhook URL已经更新为你的Heroku应用域名 +
/webhook(比如https://your-app-name.herokuapp.com/webhook) - Webhook的验证Token和代码里的完全一致,而且你得处理Facebook的GET验证请求——很多人会漏掉这个!Facebook首次配置Webhook时会发GET请求验证Token,你需要加这段逻辑:
app.get('/webhook/', function(req, res) { const YOUR_VERIFY_TOKEN = '你设置的验证令牌'; if (req.query['hub.verify_token'] === YOUR_VERIFY_TOKEN) { res.send(req.query['hub.challenge']); } else { res.send('Invalid verify token'); } });
如果没写这段,Facebook会无法验证你的Webhook,根本不会发送POST请求过来。
- 别忘了用
body-parser解析JSON请求体!Facebook的Webhook发送的是JSON格式数据,你需要在代码开头加:
const bodyParser = require('body-parser'); app.use(bodyParser.json());
不然req.body会是空的,自然读不到entry数据。
3. 依赖安装没到位
确保package.json里把node-schedule放在dependencies(不是devDependencies)里,因为Heroku只会安装dependencies下的包。部署时可以看一下Heroku的构建日志,确认node-schedule被成功安装了。
4. 代码逻辑的潜在问题
你的代码里有个容易踩坑的点:定时任务依赖的messaging_events是来自当前POST请求的参数,但定时任务执行时,这个请求已经结束了,变量的上下文早就失效了,数据也可能不对。而且每次收到Webhook请求就创建一个新的定时任务,时间长了会有一堆重复任务在跑。
正确的做法是:
- 把需要处理的用户ID、消息内容等数据存到数据库(比如Heroku自带的PostgreSQL),定时任务执行时从数据库里读取数据再发送消息,不要依赖请求时的临时变量。
- 不要在每次Webhook请求里创建定时任务,应该在应用启动时创建一次,或者用一个变量来管理已有的任务(比如用
Map存储任务实例,避免重复创建)。
快速排查步骤
- 先看Heroku日志:在终端运行
heroku logs --tail,然后触发Webhook请求,看看有没有报错信息(比如Cannot read property 'entry' of undefined,大概率是没加body-parser导致req.body为空)。 - 测试简单定时任务:写个每分钟打印日志的小任务,看看Heroku日志里有没有输出,排除
node-schedule本身的问题:
const schedule = require('node-schedule'); schedule.scheduleJob('* * * * *', function(){ console.log('定时任务执行了!'); });
内容的提问来源于stack exchange,提问作者pycan
相关产品推荐
相关产品推荐

