部署在Azure/AWS的Django对接Graph API端点验证超时问题
Microsoft Graph API Outlook Webhook 云部署验证超时问题
问题概述
本地通过ngrok暴露公网对接Microsoft Graph API配置Outlook Webhook一切正常,但迁移到Azure/AWS云平台后,每次创建订阅都会收到ValidationError: Subscription validation request timed out错误。
测试情况
用curl直接测试Azure端点,返回200 OK,验证逻辑正常:
curl -X POST https://db.chainfill.bluewaterfall.nl/email-integration/emails?validationToken=someToken -H "Accept: text/plain" -v
但Graph API发送订阅验证请求时,后端存在严重延迟——Graph返回超时错误后,后端才收到验证请求并返回200。
超时错误信息
Starting new HTTPS connection (1): graph.microsoft.com:443 https://graph.microsoft.com:443 "POST /v1.0/subscriptions HTTP/1.1" 400 None Graph API Error: {'error': {'code': 'ValidationError', 'message': 'Subscription validation request timed out.', 'innerError': {'date': '2024-05-14T16:12:13', 'request-id': 'eb76a2e1-95c7-439c-aaca-6efaf031723d', 'client-request-id': 'eb76a2e1-95c7-439c-aaca-6efaf031723d'}}}
后端延迟接收日志
Response for /email-integration/subscription with headers: {'Content-Type': 'application/json', 'Vary': 'Accept, origin', 'Allow': 'POST, OPTIONS', 'X-Frame-Options': 'DENY', 'Content-Length': '42', 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'same-origin', 'Cross-Origin-Opener-Policy': 'same-origin'} Response Status Code: 200 Response Content Type: application/json Incoming request at /email-integration/emails with headers: {'Host': 'db.chainfill.bluewaterfall.nl', 'X-Real-Ip': '137.135.11.116', 'X-Forwarded-For': '137.135.11.116', 'X-Forwarded-Proto': 'https', 'Connection': 'close', 'Content-Length': '0', 'Client-Request-Id': 'eb76a2e1-95c7-439c-aaca-6efaf031723d', 'Accept': 'text/plain', 'Content-Type': 'text/plain; charset=utf-8'} Request Path: /email-integration/emails Request Method: POST Request Query Params: <QueryDict: {'validationToken': ['Validation: Testing client application reachability for subscription Request-Id: eb76a2e1-95c7-439c-aaca-6efaf031723d']}> Accept Headers: text/plain Request URL: https://db.chainfill.bluewaterfall.nl/email-integration/emails?validationToken=Validation%3a+Testing+client+application+reachability+for+subscription+Request-Id%3a+eb76a2e1-95c7-439c-aaca-6efaf031723d validation_token Validation: Testing client application reachability for subscription Request-Id: eb76a2e1-95c7-439c-aaca-6efaf031723d Received validation token Response for /email-integration/emails with headers: {'Content-Type': 'text/plain', 'X-Frame-Options': 'DENY', 'Content-Length': '117', 'Vary': 'origin', 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'same-origin', 'Cross-Origin-Opener-Policy': 'same-origin'} Response Status Code: 200 Response Content Type: text/plain
验证请求处理代码(Django视图)
@method_decorator(csrf_exempt, name='dispatch') class GetMailsFromOutlookView(View): """Fetches an email from outlook when a new email is received""" queryset = UserProfile.objects.all() serializer_class = UserProfileSerializer # Need to secure this route still def post(self, request, *args, **kwargs): global last_processed debounce_period = 30 try: logging.debug(f'Request URL: {request.build_absolute_uri()}') # Retrieve the validation token from the query parameters validation_token = request.GET.get('validationToken') logging.debug(f'validation_token {validation_token}') if validation_token: logging.debug('Received validation token') # Check the Accept header and adjust the content type of the response accordingly accept_header = request.headers.get('Accept', 'text/plain') # Default to text/plain if not specified if 'text/plain' in accept_header: return HttpResponse(validation_token, content_type="text/plain", status=200) else: return HttpResponse("Unsupported media type", status=415)
已尝试方案
- 部署到Azure云平台
- 部署到AWS云平台
- 调整端点路由配置
服务器与框架信息
- 服务器配置:Standard B2ms(2核CPU,8GB内存)
- 后端框架:Django
求解决验证超时问题的思路。
内容的提问来源于stack exchange,提问作者Bluewaterfall Solutions
相关产品推荐
相关产品推荐

