使用Microsoft Graph API创建Teams会议时遇‘请求负载不能为空’错误
我尝试用Python调用Microsoft Graph API创建Microsoft Teams在线会议,Azure AD应用已配置委托权限(delegated)OnlineMeetings.ReadWrite,使用/me/onlineMeetings端点创建会议时,持续收到以下错误:
错误:400,{"error":{"code":"General","message":"Request payload cannot be null.","innerError":{"request-id":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX","date":"2025-01-28T06:03:29","client-request-id":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"}}}
我的Python代码如下:
import requests # Azure AD App credentials CLIENT_ID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" TENANT_ID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" CLIENT_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}" # User credentials USERNAME = "XXXX@example.com" PASSWORD = "password" # Authentication def get_access_token(): data = { "grant_type": "password", "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "scope": "https://graph.microsoft.com/.default", "username": USERNAME, "password": PASSWORD, } response = requests.post(f"{AUTHORITY}/oauth2/v2.0/token", data=data) if response.status_code == 200: return response.json().get("access_token") else: raise Exception(f"Error: {response.status_code}, {response.text}") def create_teams_meeting(): try: access_token = get_access_token() # Prepare the meeting data meeting_data = { "startDateTime": "2025-01-29T10:00:00", "endDateTime": "2025-01-29T11:00:00", "subject": "Random Meeting", } # Send the request to create the meeting headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"} response = requests.post( "https://graph.microsoft.com/v1.0/me/onlineMeetings", headers=headers, json=meeting_data ) if response.status_code == 201: meeting = response.json() return meeting["joinUrl"] else: raise Exception(f"Error creating meeting: {response.status_code}, {response.text}") except Exception as e: print(f"An error occurred: {e}") return None
已排查内容:
- Access Token:令牌生成成功
- Permissions:确认Azure AD应用已拥有OnlineMeetings.ReadWrite委托权限且已获得管理员同意
- Payload:meeting_data负载包含startDateTime、endDateTime和subject,符合Microsoft Graph API文档要求
- Headers:请求已包含Authorization和Content-Type头
问题排查与解决
1. 修正日期时间格式
Microsoft Graph要求日期时间必须是带时区的ISO 8601格式,当前代码中的日期缺少时区信息,可能导致API无法解析负载,进而判定请求体为空。修改日期格式:
meeting_data = { "startDateTime": "2025-01-29T10:00:00Z", # UTC时区,末尾加Z "endDateTime": "2025-01-29T11:00:00Z", "subject": "Random Meeting", }
如果需要使用本地时区,可写成"2025-01-29T10:00:00+08:00"(东八区)。
2. 手动序列化JSON请求体
虽然requests.post的json参数会自动序列化,但某些环境下可能出现序列化异常。尝试手动序列化:
import json # 替换原请求中的json参数为data参数 response = requests.post( "https://graph.microsoft.com/v1.0/me/onlineMeetings", headers=headers, data=json.dumps(meeting_data) )
3. 显式指定权限范围
当前使用的https://graph.microsoft.com/.default范围虽包含已配置权限,但显式指定所需权限可确保令牌包含正确的权限声明:
# 修改get_access_token函数中的scope字段 "data": { # ...其他参数 "scope": "OnlineMeetings.ReadWrite https://graph.microsoft.com/.default", }
4. 验证请求头正确性
打印请求头确认Content-Type是否被正确设置:
print(headers)
确保输出中包含"Content-Type": "application/json",若被覆盖,可尝试重新设置或检查环境是否有拦截修改请求头的情况。
5. 使用官方SDK简化调用
直接使用requests库容易出现序列化或权限问题,推荐使用Microsoft Graph Python SDK,自动处理请求细节:
from msgraph import GraphServiceClient from msgraph.generated.models.online_meeting import OnlineMeeting from azure.identity import UsernamePasswordCredential CLIENT_ID = "your-client-id" TENANT_ID = "your-tenant-id" USERNAME = "your-username" PASSWORD = "your-password" # 初始化凭证与客户端 credential = UsernamePasswordCredential(CLIENT_ID, USERNAME, PASSWORD, tenant_id=TENANT_ID) client = GraphServiceClient(credential, scopes=["OnlineMeetings.ReadWrite"]) # 创建会议对象 meeting = OnlineMeeting( start_date_time="2025-01-29T10:00:00Z", end_date_time="2025-01-29T11:00:00Z", subject="Random Meeting" ) # 发送请求 result = client.me.online_meetings.post(meeting) print(result.join_url)
内容的提问来源于stack exchange,提问作者mohannad

