背景 Facebook Messenger 是全球最大的即时通讯平台之一,月活超过 10 亿。通过 Messenger Bot 可以构建自动化的客户服务、游戏助手、营销推广等应用。这篇文章记录我从零开始搭建 Messenger Bot 的过程,包括主页配置、Node.js Webhook 服务器搭建、消息处理逻辑实现,以及 Nginx HTTPS 部署的完整流程。
Messenger Bot 架构概览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ┌─────────────────────────────────────────────────────────────────────┐ │ Facebook Messenger Bot 架构 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 用户 开发者│ │ │ │ │ │ │ 发送消息 │ │ │ ▼ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │ │ │ Facebook │ ───────► │ Messenger │ ───────► │ Webhook │ │ │ │ Messenger │ │ Platform │ │ Server │ │ │ └──────────────┘ └──────────────┘ └────┬─────┘ │ │ │ │ │ ▼ │ │ ┌────────────┐ │ │ │ Node.js │ │ │ │ Express │ │ │ └────────────┘ │ │ │ │ 关键组件: │ │ • Facebook 主页(Page)- 机器人的身份标识 │ │ • Messenger 应用 - 平台接入点 │ │ • Webhook 服务器 - 接收消息事件 │ │ • 消息处理逻辑 - 业务响应 │ │ │ └─────────────────────────────────────────────────────────────────────┘
前置条件与服务器要求 服务器环境要求
需求
说明
推荐方案
HTTPS 支持
Facebook 强制要求 Webhook 使用 HTTPS
Nginx + SSL 证书
公网 IP
服务器必须能被 Facebook 访问
云服务器(ECS/VPS)
Node.js
运行环境
v8.x 或更高版本
域名
SSL 证书绑定
一级域名(推荐)
SSL 证书注意事项
重要提示 :申请 SSL 证书绑定的域名建议使用一级域名(如 bot.example.com)。二级域名在某些 Nginx 配置场景下可能出现兼容性问题。阿里云等平台提供免费的 DV SSL 证书,有效期一年。
第一步:创建 Facebook 主页 Messenger Bot 必须关联一个 Facebook 主页,主页将作为机器人的”身份”与用户交互。
主页创建要求 1 2 3 4 5 6 7 8 9 10 11 12 ┌─────────────────────────────────────────────────────────────┐ │ Facebook 主页创建规范 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 必填条件: │ │ ✓ 主页类别必须是"应用主页"或"公司、组织或机构" │ │ ✓ 主页名称需要包含应用名称 │ │ ✓ 主页不能与其他应用关联 │ │ │ │ 创建地址:https://www.facebook.com/pages/creation/ │ │ │ └─────────────────────────────────────────────────────────────┘
配置主页 Messenger 设置 创建主页后,需要进行以下配置:
进入主页的 设置 > Messenger 开放平台
在 通用设置 中找到 已订阅应用
点击 身份 ,选择 “Primary Receiver” (主要接收者)
关联小游戏(可选) 如果 Bot 用于游戏场景,需要将小游戏应用与主页关联:
进入小游戏应用的 详情 > 应用主页板块
选择刚创建的主页
注意 :如果小游戏未与正确类型的主页关联,智能助手将无法收到 messaging_game_plays 事件
第二步:搭建 Node.js Webhook 服务器 项目初始化 创建项目目录并初始化:
1 2 3 mkdir messenger-bot-servercd messenger-bot-servernpm init -y
package.json 配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { "name" : "messenger-bots" , "version" : "1.0.0" , "description" : "An webhook for Facebook Messenger." , "main" : "app.js" , "scripts" : { "start" : "node app.js" } , "dependencies" : { "body-parser" : "^1.15.0" , "express" : "^4.13.4" , "request" : "^2.72.0" } , "engines" : { "node" : ">=8.0.0" } }
安装依赖:
核心服务代码:app.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 'use strict' ;const request = require ('request' );const express = require ('express' );const body_parser = require ('body-parser' );const app = express ().use (body_parser.json ());const VERIFY_TOKEN = 'your_verify_token_here' ; const PAGE_ACCESS_TOKEN = 'your_page_access_token' ; const PORT = process.env .PORT || 1337 ;app.listen (PORT , () => { console .log (`Webhook server is listening on port ${PORT} ` ); }); app.get ('/webhook' , (req, res ) => { let mode = req.query ['hub.mode' ]; let token = req.query ['hub.verify_token' ]; let challenge = req.query ['hub.challenge' ]; if (mode && token) { if (mode === 'subscribe' && token === VERIFY_TOKEN ) { console .log ('WEBHOOK_VERIFIED' ); res.status (200 ).send (challenge); } else { res.sendStatus (403 ); } } }); app.post ('/webhook' , (req, res ) => { let body = req.body ; if (body.object === 'page' ) { body.entry .forEach (function (entry ) { let webhook_event = entry.messaging [0 ]; console .log ('Received event:' , webhook_event); let sender_psid = webhook_event.sender .id ; console .log ('Sender PSID:' , sender_psid); if (webhook_event.message ) { handleMessage (sender_psid, webhook_event.message ); } else if (webhook_event.postback ) { handlePostback (sender_psid, webhook_event.postback ); } else if (webhook_event.game_play ) { handleGamePlay (sender_psid, webhook_event.game_play ); } }); res.status (200 ).send ('EVENT_RECEIVED' ); } else { res.sendStatus (404 ); } });
消息处理函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 function handleMessage (sender_psid, received_message ) { let response; if (received_message.text ) { const text = received_message.text .toLowerCase (); if (text.includes ('help' ) || text.includes ('帮助' )) { response = { "text" : "可用命令:\n• 游戏 - 开始游戏\n• 帮助 - 查看帮助\n• 状态 - 查看账户状态" }; } else if (text.includes ('游戏' ) || text.includes ('game' )) { response = { "attachment" : { "type" : "template" , "payload" : { "template_type" : "generic" , "elements" : [{ "title" : "我的小游戏" , "subtitle" : "点击开始游玩" , "buttons" : [{ "type" : "game_play" , "title" : "开始游戏" }] }] } } }; } else { response = { "text" : `收到消息:"${received_message.text} "` }; } } callSendAPI (sender_psid, response); } function handlePostback (sender_psid, received_postback ) { let response; let payload = received_postback.payload ; if (payload === 'GET_STARTED' ) { response = { "text" : "欢迎使用!发送" 帮助"查看可用命令。" }; } else { response = { "text" : "收到按钮点击事件" }; } callSendAPI (sender_psid, response); } function handleGamePlay (sender_psid, game_play ) { let playerId = game_play.player_id ; let contextId = game_play.context_id ; console .log (`Player ${playerId} started playing in context ${contextId} ` ); let response = { "text" : `欢迎回来!你的玩家 ID 是 ${playerId} ` }; callSendAPI (sender_psid, response); }
发送消息 API 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function callSendAPI (sender_psid, response ) { let request_body = { "recipient" : { "id" : sender_psid }, "message" : response }; console .log ('Sending message:' , JSON .stringify (request_body)); request ({ "uri" : "https://graph.facebook.com/v2.6/me/messages" , "qs" : { "access_token" : PAGE_ACCESS_TOKEN }, "method" : "POST" , "json" : request_body }, (err, res, body ) => { if (!err) { console .log ('Message sent successfully!' ); } else { console .error ('Unable to send message:' , err); } }); }
第三步:Nginx HTTPS 配置 SSL 证书部署 将申请的 SSL 证书文件放置到服务器目录:
1 2 3 mkdir -p /data/sslcp your_certificate.pem /data/ssl/cp your_private.key /data/ssl/
Nginx 配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 server { listen 443 ssl; server_name bot.yourdomain.com; ssl_certificate /data/ssl/your_certificate.pem; ssl_certificate_key /data/ssl/your_private.key; ssl_session_cache shared:SSL:1m ; ssl_session_timeout 5m ; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 ; ssl_prefer_server_ciphers on ; server_tokens off ; add_header Strict-Transport-Security "max-age=31536000" always; fastcgi_param HTTPS on ; fastcgi_param HTTP_SCHEME https; access_log /var/log/nginx/messenger-access.log; error_log /var/log/nginx/messenger-error .log; location / { proxy_pass http://localhost:1337; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_redirect http:// $scheme ://; proxy_http_version 1 .1 ; proxy_set_header Upgrade $http_upgrade ; proxy_set_header Connection "upgrade" ; } } server { listen 80 ; server_name bot.yourdomain.com; return 301 https://$server_name $request_uri ; }
使用 PM2 管理 Node.js 进程 1 2 3 4 5 6 7 8 9 10 11 12 13 npm install -g pm2 pm2 start app.js --name "messenger-bot" pm2 startup pm2 save pm2 status pm2 logs messenger-bot
第四步:配置 Messenger 平台 添加 Messenger 产品 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ┌─────────────────────────────────────────────────────────────┐ │ Messenger 平台配置流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. 进入 Facebook 开发者控制台 │ │ https://developers.facebook.com/apps/ │ │ │ │ 2. 选择你的应用 │ │ │ │ 3. 在左侧"产品"面板点击"+ 添加产品" │ │ │ │ 4. 找到 Messenger 并点击"设置" │ │ │ │ 5. 在 Messenger 设置页面配置以下项: │ │ │ └─────────────────────────────────────────────────────────────┘
配置 Webhook 在 Messenger 设置的 Webhooks 版块:
配置项
填写内容
说明
回调网址
https://bot.yourdomain.com/webhook
你的 Webhook 地址
验证口令
与 VERIFY_TOKEN 一致
用于验证请求合法性
订阅字段
messages, messaging_postbacks, messaging_game_plays
需要接收的事件类型
点击 “验证并保存” ,Facebook 会发送 GET 请求验证你的服务器。
订阅主页并获取访问口令
在 生成口令 版块,选择之前创建的主页
复制 主页访问口令 ,更新到 app.js 的 PAGE_ACCESS_TOKEN 变量
在 Webhooks 版块,选择同一主页并点击 订阅
Webhook 事件类型说明
事件类型
触发场景
用途
messages
用户发送文本/附件消息
处理用户输入
messaging_postbacks
用户点击按钮
处理菜单交互
messaging_game_plays
用户开始游玩 Instant Game
游戏场景联动
messaging_deliveries
消息送达确认
投递状态追踪
messaging_reads
消息已读确认
阅读状态追踪
进阶功能实现 发送结构化消息(卡片模板) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function sendGenericTemplate (sender_psid ) { let response = { "attachment" : { "type" : "template" , "payload" : { "template_type" : "generic" , "elements" : [{ "title" : "游戏礼包" , "image_url" : "https://example.com/gift.png" , "subtitle" : "每日登录领取超值礼包" , "buttons" : [ { "type" : "postback" , "title" : "领取礼包" , "payload" : "CLAIM_GIFT" }, { "type" : "web_url" , "url" : "https://example.com/shop" , "title" : "前往商店" } ] }] } } }; callSendAPI (sender_psid, response); }
设置欢迎界面(Get Started) 通过 Messenger Profile API 设置欢迎按钮:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function setGetStartedButton ( ) { request ({ "uri" : "https://graph.facebook.com/v2.6/me/messenger_profile" , "qs" : { "access_token" : PAGE_ACCESS_TOKEN }, "method" : "POST" , "json" : { "get_started" : { "payload" : "GET_STARTED" }, "greeting" : [ { "locale" : "default" , "text" : "你好!我是游戏助手,发送" 帮助"开始探索。" } ] } }, (err, res, body ) => { if (!err) { console .log ('Get Started button set successfully' ); } }); }
调试与常见问题 本地调试技巧 1 2 3 4 5 6 7 8 9 curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.listsudo apt update && sudo apt install ngrokngrok http 1337
常见问题排查
问题
原因
解决方案
Webhook 验证失败
VERIFY_TOKEN 不匹配
检查 app.js 和 Facebook 控制台配置是否一致
消息发送失败
PAGE_ACCESS_TOKEN 无效
重新生成主页访问口令
无法接收游戏事件
主页未正确关联
确认主页类别和关联关系
SSL 错误
证书配置问题
检查 Nginx SSL 配置和证书路径
小结 搭建 Facebook Messenger Bot 的主要步骤:
创建主页 :确保主页类别正确,与应用正确关联
搭建服务器 :使用 Express.js 实现 Webhook 接收端点
部署 HTTPS :通过 Nginx 反向代理提供安全的 Webhook 地址
配置平台 :在 Messenger 设置中完成 Webhook 验证和事件订阅
处理消息 :根据业务需求实现消息解析和响应逻辑
测试验证 :通过 Messenger 发送消息确认 Bot 正常工作
这套方案可以构建功能完善的 Messenger 智能助手,支持文本交互、卡片模板、游戏联动等多种场景。