如何在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
相关产品推荐
相关产品推荐

