You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js/Express环境下ServiceM8 Webhook挑战验证返回“Invalid callback challenge key returned”的问题咨询

解决ServiceM8 Webhook订阅挑战验证失败问题

我之前在Express环境下成功配置过ServiceM8 Webhook,刚好遇到过类似的问题,给你梳理下解决方案:

首先明确:ServiceM8的订阅挑战请求是通过GET方式发送的,请求参数mode=subscribe和challenge=xxx都会放在URL的query里,不会出现在请求body中。

你的代码可能存在的问题

虽然你用了app.all来处理所有请求方法,但有两个潜在坑:

  1. 你同时尝试从req.body取challenge和mode,但GET请求默认不会有body(除非你强制配置了body解析中间件处理GET),这可能导致逻辑混乱,但不是核心问题。
  2. 最关键的是:ServiceM8要求挑战响应必须是纯文本格式的challenge值,不能有任何额外的字符(比如HTML标签、空格、换行),也不能返回JSON。你的代码用res.send(challenge)虽然默认会返回字符串,但Express可能会自动设置Content-Type: text/html,部分情况下ServiceM8会对这个类型不敏感,但如果你的服务器有其他中间件(比如日志、压缩)添加了额外响应头或内容,就会导致验证失败。

正确的实现代码

建议分开处理GET(验证订阅)和POST(接收事件)请求,避免混淆:

// 处理订阅验证的GET请求
app.get('/webhook/job-complete', (req, res) => {
  const { mode, challenge } = req.query;

  // 严格匹配模式和挑战参数
  if (mode === 'subscribe' && typeof challenge === 'string') {
    // 明确设置返回纯文本,确保没有额外内容
    return res.status(200).type('text/plain').send(challenge.trim());
  }

  // 无效请求返回400,不要返回200,避免ServiceM8误判
  res.sendStatus(400);
});

// 处理实际Webhook事件的POST请求
app.post('/webhook/job-complete', express.json(), (req, res) => {
  // 这里处理实际的事件数据
  console.log('收到ServiceM8事件:', req.body);
  
  // 必须返回200状态码确认接收,否则ServiceM8会重试
  res.sendStatus(200);
});

额外检查项

  1. 公网可访问性:确保你的Express服务器能被公网访问(可以用ngrok临时测试),ServiceM8无法访问内网地址。
  2. 测试验证请求:用curl模拟ServiceM8的GET请求,确认返回的是纯文本的challenge:
    curl "http://你的服务器地址/webhook/job-complete?mode=subscribe&challenge=29c97899930d7b3c"
    
    检查返回结果是否就是29c97899930d7b3c,没有任何其他字符。
  3. 中间件干扰:检查是否有中间件(比如morgan日志、compression压缩)在响应中添加了额外内容,这会导致挑战值不匹配。

我用这个配置成功通过了ServiceM8的验证,你可以试试调整后重新订阅。

内容的提问来源于stack exchange,提问作者user32528474

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 10:22:29