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

使用Google Cloud Function配置Meta WhatsApp Cloud API Webhook验证失败

问题

在Google Cloud Function中搭建Webhook用于接收WhatsApp Business API消息并转发至Front平台时,Meta for WhatsApp配置Webhook时出现错误:
The callback URL or verify token couldn't be validated. Please verify the provided information or try again later.

已确认WhatsApp Business API凭证、Webhook URL配置正确,Google Cloud Function已部署可访问,但查看日志发现验证Webhook时出现:Received message with missing contacts or messages property. Skipping message processing,尝试返回200状态码仍无法解决。

相关代码如下:

const axios = require('axios');

const FRONT_API_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsicHJvdmlzaW9uaW5nIiwicHJpdmF0ZToqIiwic2hhcmVkOioiXSwiaWF0IjoxNjc5NTE0MDU1LCJpc3MiOiJmcm9udCIsInN1YiI6ImI4MGUzZDExODQyMDUzZTk5OGE0IiwianRpIjoiYmM5NzNlNGQyZTA3YTAzMiJ9.7LBqJ5Kw3O65c4GttZuh4K2Zt7fkGIIq9yI96l06TJ8';
const FRONT_CUSTOM_CHANNEL_WEBHOOK_URL = 'https://api2.frontapp.com/channels/cha_ak6s0/incoming_messages';
const VERIFY_TOKEN = 'whatsappfronttoken';

const handleVerification = (req, res) => {
  const queryToken = req.query.verify_token;
  console.log('Verification request received:', req.query);
  if (queryToken === VERIFY_TOKEN) {
    res.send(req.query.challenge);
  } else {
    console.error('Invalid verify token:', queryToken);
    res.sendStatus(403);
  }
};

exports.whatsappHandler = async (req, res) => {
  if (req.query.verify_token) {
    handleVerification(req, res);
  } else {
    const message = req.body;

    if (!message.contacts || !message.messages) {
      console.warn('Received message with missing contacts or messages property. Skipping message processing.');
      res.sendStatus(200);
      return;
    }

    // Extract relevant information from the WhatsApp message
    const sender = message.contacts[0].profile.name || message.contacts[0].wa_id;
    const text = message.messages[0].text.body;

    // Format the message for Front's custom channel webhook URL
    const formattedMessage = {
      sender: {
        name: sender,
        handle: sender,
      },
      subject: 'WhatsApp Message',
      body: text,
      body_format: 'markdown',
    };

    // Forward the message to Front's custom channel webhook URL
    try {
      await axios.post(FRONT_CUSTOM_CHANNEL_WEBHOOK_URL, formattedMessage, {
        headers: {
          'Authorization': `Bearer ${FRONT_API_TOKEN}`,
        },
      });
      res.sendStatus(200);
    } catch (error) {
      console.error(error);
      res.sendStatus(500);
    }
  }
};
原因分析

Meta的Webhook验证请求是POST请求,不会携带verify_token查询参数,而是将验证信息(hub.mode、hub.verify_token、hub.challenge)放在请求体中。当前代码仅在req.query.verify_token存在时才处理验证逻辑,导致验证请求被误判为普通消息请求,进入后续分支后因缺少contacts和messages字段触发警告,最终虽然返回200,但没有正确响应Meta的验证要求。

解决方法

修改whatsappHandler函数,优先通过请求体中的hub.mode字段判断是否为验证请求,替换原有的查询参数判断逻辑:

exports.whatsappHandler = async (req, res) => {
  // 处理Meta的Webhook验证请求
  const { hub } = req.body;
  if (hub?.mode === 'subscribe' && hub?.verify_token === VERIFY_TOKEN) {
    res.send(hub.challenge);
    return;
  }

  // 处理普通的WhatsApp消息请求
  const message = req.body;

  if (!message.contacts || !message.messages) {
    console.warn('Received message with missing contacts or messages property. Skipping message processing.');
    res.sendStatus(200);
    return;
  }

  // 原有的消息转发逻辑保持不变
  const sender = message.contacts[0].profile.name || message.contacts[0].wa_id;
  const text = message.messages[0].text.body;

  const formattedMessage = {
    sender: {
      name: sender,
      handle: sender,
    },
    subject: 'WhatsApp Message',
    body: text,
    body_format: 'markdown',
  };

  try {
    await axios.post(FRONT_CUSTOM_CHANNEL_WEBHOOK_URL, formattedMessage, {
      headers: {
        'Authorization': `Bearer ${FRONT_API_TOKEN}`,
      },
    });
    res.sendStatus(200);
  } catch (error) {
    console.error(error);
    res.sendStatus(500);
  }
};

额外注意事项:

  • 确保Google Cloud Function的触发方式为HTTP触发,允许所有请求方法(尤其是POST)
  • 验证请求的响应需直接返回hub.challenge的原始内容,不能添加额外格式或状态码包装

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:42:42