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

如何在Django中接收WhatsApp Webhook事件?问题排查

Django WhatsApp Webhook 接收失败排查方案

核心问题

你的Django视图本地模拟POST请求正常,但无法接收实际WhatsApp事件,而PHP版本可正常工作。以下是针对性的排查步骤和解决方案:


1. 先确认Webhook基础配置

公网可达性

  • 确保Django服务部署在公网可访问的服务器上(本地服务需用ngrok等内网穿透工具),WhatsApp无法直接访问本地localhost地址。
  • 检查服务器防火墙/安全组,开放Django服务的端口(默认8000或自定义端口),允许WhatsApp服务器的IP段访问。
  • 核对WhatsApp后台配置的Webhook URL,必须和Django路由完全一致(比如PHP用/webhook,Django不能写成/home)。

Webhook验证(关键)

如果使用Meta WhatsApp Business Platform,必须先完成GET请求的验证步骤,否则WhatsApp不会发送任何事件。PHP代码可能已经处理了验证,而Django视图缺失这部分逻辑:

@csrf_exempt
def home(request):
    # 处理Meta Webhook验证
    if request.method == 'GET':
        hub_mode = request.GET.get('hub.mode')
        hub_token = request.GET.get('hub.verify_token')
        hub_challenge = request.GET.get('hub.challenge')
        
        # 替换为你在WhatsApp后台设置的验证令牌
        YOUR_VERIFY_TOKEN = "your_custom_token"
        
        if hub_mode == 'subscribe' and hub_token == YOUR_VERIFY_TOKEN:
            return HttpResponse(hub_challenge, status=200)
        else:
            return HttpResponse('Invalid token', status=403)
    
    # 处理POST事件逻辑...

2. 排查请求解析问题

WhatsApp发送的请求可能不是标准application/json格式,PHP用file_get_contents('php://input')可以兼容所有格式,但Django直接解析JSON可能失败。先修改视图记录原始请求,明确WhatsApp的实际请求格式:

import datetime
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
import os
import json

@csrf_exempt
def home(request):
    # 记录原始请求到文件,排查实际请求内容
    raw_log_path = os.path.join(settings.BASE_DIR, 'raw_webhook_log.txt')
    with open(raw_log_path, 'ab') as f:
        f.write(b"=== " + str(datetime.datetime.now()).encode() + b" ===\n")
        f.write(f"Method: {request.method}\n".encode())
        f.write(f"Headers: {dict(request.headers)}\n".encode())
        f.write(b"Body:\n")
        f.write(request.body)
        f.write(b"\n\n")

    if request.method == 'POST':
        try:
            # 尝试多种解析方式
            try:
                data = json.loads(request.body)
            except json.JSONDecodeError:
                # 尝试解析表单格式数据
                data = request.POST.dict()
                # 部分服务会把JSON放在payload字段中
                if 'payload' in data:
                    data = json.loads(data['payload'])

            # 写入格式化日志
            log_path = os.path.join(settings.BASE_DIR, 'messages_log.txt')
            with open(log_path, 'a') as f:
                f.write(f"{datetime.datetime.now()}: {json.dumps(data, indent=2)}\n")

            return JsonResponse({'status': 'received'}, status=200)
        except Exception as e:
            # 记录错误信息
            error_log_path = os.path.join(settings.BASE_DIR, 'webhook_error.txt')
            with open(error_log_path, 'a') as f:
                f.write(f"{datetime.datetime.now()}: {str(e)}\n")
            return JsonResponse({'status': 'error'}, status=500)
    
    return JsonResponse({'status': 'Method Not Allowed'}, status=405)

查看raw_webhook_log.txt,可以明确WhatsApp发送的请求头、数据格式,针对性调整解析逻辑。


3. 修复视图潜在问题

CSRF豁免与请求方法限制

确保@csrf_exempt生效,同时明确只接受POST请求(WhatsWebhook仅发POST):

@csrf_exempt
@require_http_methods(["POST", "GET"])  # GET用于验证,POST用于事件
def home(request):
    # 你的代码

文件写入权限与路径问题

避免用os.getcwd(),改用Django项目根目录确保路径可靠,同时检查运行Django的用户是否有文件写入权限:

from django.conf import settings

# 用项目根目录作为基准路径
log_path = os.path.join(settings.BASE_DIR, 'messages_log.txt')

响应超时问题

WhatsApp要求Webhook在10秒内返回响应,若处理逻辑耗时,可改用异步线程处理:

import threading

def process_data(raw_data):
    try:
        data = json.loads(raw_data)
        log_path = os.path.join(settings.BASE_DIR, 'messages_log.txt')
        with open(log_path, 'a') as f:
            f.write(f"{datetime.datetime.now()}: {json.dumps(data, indent=2)}\n")
    except Exception as e:
        with open(os.path.join(settings.BASE_DIR, 'webhook_error.txt'), 'a') as f:
            f.write(f"{datetime.datetime.now()}: {str(e)}\n")

@csrf_exempt
def home(request):
    if request.method == 'POST':
        raw_data = request.body.decode('utf-8')
        # 异步处理数据,快速返回响应
        threading.Thread(target=process_data, args=(raw_data,)).start()
        return JsonResponse({'status': 'received'}, status=200)
    # 验证逻辑...

4. 查看Django日志

检查Django的服务器日志(默认在控制台或指定日志文件),重点关注:

  • 404错误:路由配置错误,URL不匹配
  • 403错误:CSRF豁免失效,或验证令牌错误
  • 500错误:视图代码异常(如文件写入失败、JSON解析错误)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:15:02