在AWS Lambda部署Flask版Teams Bot时遭遇'httpMethod' KeyError问题
问题:AWS托管Teams Bot触发Lambda时出现KeyError: 'httpMethod'
错误信息
{"errorMessage": "'httpMethod'", "errorType": "KeyError", "requestId": "b1d5275e-60cc-489f-8079-0fc701412b69", "stackTrace": [" File \"/var/task/app.py\", line 72, in lambda_handler\n return awsgi.response(app, event, context)\n", " File \"/opt/python/awsgi/__init__.py\", line 172, in response\n output = app(environ(event, context), sr)\n", " File \"/opt/python/awsgi/__init__.py\", line 121, in environ\n 'REQUEST_METHOD': event['httpMethod'],\n"]}
相关代码
app.py
import sys import traceback import json from datetime import datetime import awsgi import asyncio from flask import Flask, request, jsonify from botbuilder.core import BotFrameworkAdapterSettings, TurnContext, BotFrameworkAdapter from botbuilder.schema import Activity, ActivityTypes from bot import MyBot from config import DefaultConfig CONFIG = DefaultConfig() # Create adapter. SETTINGS = BotFrameworkAdapterSettings(CONFIG.APP_ID, CONFIG.APP_PASSWORD) ADAPTER = BotFrameworkAdapter(SETTINGS) # Catch-all for errors. async def on_error(context: TurnContext, error: Exception): print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr) traceback.print_exc() # Send a message to the user await context.send_activity("The bot encountered an error or bug.") await context.send_activity("To continue to run this bot, please fix the bot source code.") # Send a trace activity if we're talking to the Bot Framework Emulator if context.activity.channel_id == "emulator": trace_activity = Activity( label="TurnError", name="on_turn_error Trace", timestamp=datetime.utcnow(), type=ActivityTypes.trace, value=f"{error}", value_type="https://www.botframework.com/schemas/error", ) await context.send_activity(trace_activity) ADAPTER.on_turn_error = on_error # Create the Bot BOT = MyBot() # Initialize Flask app app = Flask(__name__) @app.route("/api/messages", methods=["POST"]) def messages(): if request.headers.get("Content-Type") == "application/json": body = request.json else: return "Unsupported Media Type", 415 activity = Activity().deserialize(body) auth_header = request.headers.get("Authorization", "") # Create a task to handle the incoming activity async def aux_func(): await ADAPTER.process_activity(activity, auth_header, BOT.on_turn) asyncio.run(aux_func()) return jsonify({"status": "Message processed"}), 201 # AWS Lambda handler def lambda_handler(event, context): return awsgi.response(app, event, context)
bot.py
from botbuilder.core import ActivityHandler, TurnContext class MyBot(ActivityHandler): async def on_message_activity(self, turn_context: TurnContext): await turn_context.send_activity(f'message!')
问题分析与解决方案
1. 核心错误原因:API Gateway事件格式不匹配
错误提示KeyError: 'httpMethod',说明awsgi库期望的Lambda事件中缺少httpMethod字段,通常由以下原因导致:
- API Gateway未配置为Lambda代理集成:只有代理集成才会将HTTP请求元数据(包括httpMethod、headers等)封装到Lambda事件中。
- 使用API Gateway v2(HTTP API):其默认事件格式与v1(REST API)不同,awsgi无法直接解析。
2. 修复步骤
步骤1:配置API Gateway为Lambda代理集成
- 进入AWS API Gateway控制台,找到目标API。
- 在
/api/messages资源的POST方法设置中,确认集成类型为Lambda代理集成,而非普通Lambda集成。 - 重新部署API生效更改。
步骤2:修复Flask异步调用问题
原代码使用asyncio.get_event_loop()在Lambda环境易引发兼容性问题,改用asyncio.run()更稳定,同时补充缺失的asyncio模块导入。
步骤3:适配API Gateway v2(HTTP API)事件格式
如果使用HTTP API,需手动转换事件格式以适配awsgi:
def lambda_handler(event, context): # 转换HTTP API v2事件格式为awsgi兼容格式 if 'requestContext' in event and 'http' in event['requestContext']: event['httpMethod'] = event['requestContext']['http']['method'] event['path'] = event['requestContext']['http']['path'] event['headers'] = event.get('headers', {}) event['body'] = event.get('body', '') event['isBase64Encoded'] = event.get('isBase64Encoded', False) return awsgi.response(app, event, context)
3. 额外验证点
- 确认Lambda执行角色拥有CloudWatch日志、API Gateway调用等必要权限。
- 检查Teams Bot配置的消息端点与API Gateway部署URL完全一致,格式应为
https://{api-id}.execute-api.{region}.amazonaws.com/{stage}/api/messages。
内容的提问来源于stack exchange,提问作者ryn
相关产品推荐
相关产品推荐

