生产环境Viber Webhook设置失败:data参数类型错误求助
解决Viber Bot生产环境设置Webhook时报错:The "data" argument must be one of type string, TypedArray, or DataView
我刚碰到过几乎一模一样的问题,折腾半天终于找到根源——Viber Bot的中间件需要读取原始请求体(raw body)来计算HMAC签名验证,但你的Express全局配置的body-parser把请求体解析成了JSON对象,导致验证时传入Hmac.update的是对象而非原始的字符串/Buffer。本地用ngrok正常是因为本地环境的请求处理逻辑和生产环境有差异,没影响到原始请求体的获取。
错误原因分析
看错误栈里的MessageValidator._calculateHmacFromMessage调用,这里需要传入原始请求体内容生成HMAC,但全局的body-parser.json()已经把请求体解析成了JS对象,Viber中间件拿到的不是它需要的原始数据类型,所以抛出了类型错误。
解决方案(推荐第一种,路由隔离更清晰)
把body-parser的JSON解析只应用到需要的路由(比如你的/api/admin),不给Viber的webhook路由应用任何body-parser解析,让Viber中间件自己处理原始请求体:
修改你的主服务器代码:
const path = require("path"); const publicPath = path.join(__dirname, "../public"); const express = require("express"); const http = require("http"); const env = require("dotenv"); const bodyParser = require("body-parser"); env.config({ path: path.resolve(__dirname + "/.env") }); const app = express(); const server = http.createServer(app); const adminActionRoute = require('./routes/admin'); app.use(express.static(publicPath)); // 只给/admin路由应用body-parser解析,不要全局配置 app.use('/api/admin', bodyParser.json({ verify: verifyRequestSignature })); app.use('/api/admin', bodyParser.urlencoded({ limit: '200mb', extended: true })); app.use('/api/admin', adminActionRoute); const viberBot = require('../viber_chat/utils/bot') // Viber webhook路由直接使用中间件,不经过body-parser的JSON解析 app.use('/viber/webhook', viberBot.middleware()) server.listen(5000, () => { viberBot.setWebhook(process.env.VB_WEBHOOK_URL); console.log("server starts at port 5000"); }); module.exports = server; //for testing
备选方案(如果必须全局解析JSON)
如果你的其他路由需要全局JSON解析,可以在body-parser的verify函数里把原始请求体存到req.rawBody,让Viber中间件能读取到:
function verifyRequestSignature(req, res, buf) { // 保存原始请求体到req.rawBody req.rawBody = buf; // 你的原有签名验证逻辑... } // 全局配置,但保留原始请求体 app.use(bodyParser.json({ verify: verifyRequestSignature })); app.use(bodyParser.urlencoded({ limit: '200mb', extended: true })); // Viber中间件会自动读取req.rawBody(部分viber-bot版本支持,不确定的话优先用第一种方案) app.use('/viber/webhook', viberBot.middleware())
额外检查点
- 确认生产环境的
VB_WEBHOOK_URL是公网可访问的,且Viber服务器能正常请求到 - 检查生产环境的
VB_API_KEY是否正确加载(可以在启动时打印出来验证) - 如果用了反向代理(比如Nginx),确保配置里没有修改请求体,并且传递了正确的
Content-Type头
内容的提问来源于stack exchange,提问作者Thet Htun
相关产品推荐
相关产品推荐

