嗨各位,
我在驗證 Meta/WhatsApp Business API Webhook 時完全卡住了。Meta 一直以標準錯誤拒絕:「無法驗證回調 URL 或驗證令牌」。
我已經把問題隔離到 n8n 返回響應的方式,但我無法理解為什麼它會失敗。
以下是我的設置:
- 托管: 通過 Docker(Windows)自行托管 n8n。
- 隧道: Cloudflare Tunnels(
.trycloudflare.com)。
- 觸發節點: Webhook 節點,方法 GET,路徑
whatsapp-incoming。Respond 選項嚴格設置為**「使用 ‘Respond to Webhook’ 節點」**。
- 響應節點: ‘Respond to Webhook’ 節點。
Respond With 設置為文本。Response Body 表達式正好是:{{ $json.query["hub.challenge"] }}。
以下是我遇到的奇怪行為:
- 網絡正常: Meta 的請求成功到達我的 n8n 實例。
- 執行成功: 在「執行」選項卡中,工作流完美完成並顯示綠色「成功」狀態。
- 表達式解析正確: 當我檢查「Respond to Webhook」節點的執行詳情時,它成功捕獲並預覽了 Meta 發送的確切質詢號。
- 問題所在(無聲失敗): 當我通過瀏覽器手動測試 URL(例如
https://my-cloudflare-url/webhook/whatsapp-incoming?hub.challenge=11223344)時,n8n 記錄了一次成功的執行,但瀏覽器顯示完全空白的白屏。它沒有返回文本,甚至沒有返回錯誤消息。它返回了空的響應體。
因為響應體是空的,而不是返回原始質詢號,Meta 拒絕了驗證。
我已經嘗試過:
- 移除「Respond to Webhook」節點中的所有額外響應頭。
- 確保表達式被計算為表達式(
fx),而不是靜態字符串。
- 重新創建 Webhook 節點。
有人遇到過「Respond to Webhook」節點執行成功但向客戶端返回空響應體的問題嗎?我是否遺漏了某項配置?
提前感謝您的任何幫助!
嘿 @Permadi,在等待回覆期間,以下是一些可能有幫助的資源:
建議的資源
自動符合您的問題。
文件:
論壇:
@Republic1815、@tridi、@Anshul_Namdev——你們之前幫助過類似的問題,能看一下嗎?
由 n8n 社群機器人自動建議。這是試點——請在此分享意見反饋。
嘿 @Permadi 歡迎來到 n8n 社群!
我認為你的設定是正確的,所以不需要切換到 JSON 或更改 URL。我測試了你的確切設定,它運作完美。
混淆來自於輸出面板。根據預設,「回應 Webhook」節點顯示的是它的 輸入,而不是它實際發送的回應。如果你的表達式解析為空,n8n 仍然會記錄一個成功的綠色執行(HTTP 200),但會發送空白正文。這正好符合你的情況。
所以打開「回應」節點,進到「設定」標籤,然後開啟「啟用回應輸出分支」來看看發送了什麼。如果是空的,表達式沒有解析(通常是因為複製了彎引號),所以手動重新輸入括號。如果它顯示 11223344,而瀏覽器仍然收不到任何內容,那就是 trycloudflare 通道丟棄了正文,這是另一個問題。
如果有幫助的話,請告訴我。
嗨 @Permadi 歡迎!
回應方式:Text 預設發送 Content-Type: text/html,而 Meta 的握手需要將挑戰以純文字形式回傳,不需要任何包裝。移除回應標頭後會保留該預設值,因此請在「回應至 Webhook」節點上明確設定,名稱為 Content-Type,值為 text/plain。
請參閱以下內容:
你的文章中有一個線索是上面的答案略過的:你的執行預覽顯示了挑戰編號,但正文到達時為空。這排除了捲曲引號理論,因為如果表達式沒有解析,你根本不會在預覽中看到編號。而且內容類型也不能完全解釋,因為 text/html 仍然會發送編號,只是使用錯誤的標頭,而不是空正文。
符合你所有證據的是類型。hub.challenge 作為數字到達,而「回應 Webhook」在文本模式下需要字符串。當它獲得裸數字時,某些構建會發送空值,這正是你執行綠色且正文為空的情況。
強制轉換為字符串並再次測試:
{{ $json.query[“hub.challenge”].toString() }}
或
{{ String($json.query[“hub.challenge”]) }}
如果瀏覽器現在顯示編號,那就是這樣,Meta 將接受握手。如 Anshul 所說,在你在那裡時將 Content-Type 標頭設置為 text/plain,因為一旦正文非空,Meta 確實想要純文本。
強制轉換為字符串後仍然為空,那麼隧道正在吃掉正文,而不是 n8n。trycloudflare 快速隧道間歇性地丟棄小正文,所以直接使用 curl -i 針對你的容器連接 URL,繞過 Cloudflare。如果 curl 顯示編號,但通過隧道的瀏覽器沒有,你就有了答案,這根本不是 n8n。