调用Google Calendar API持续返回400 Bad Request问题求助
解决Google Calendar API添加事件返回400 Bad Request的问题
问题根源分析
你的代码存在三个关键错误,直接导致了400请求失败:
请求体格式不匹配
调用requests.post时使用data=payload会把字典编码为表单数据(application/x-www-form-urlencoded),但你在请求头里声明了Content-Type: application/json,API无法解析格式不匹配的请求体。缺少必填的
summary字段
你调用add_event时传入了summary参数,但代码里没有将其加入请求的payload中。Google Calendar API创建事件时summary是必填项,缺失会直接触发400错误。OAuth2会话生命周期错误
auth方法中,session.fetch_token的代码不在with requests_oauthlib.OAuth2Session(...) as session:的代码块内,会话会在执行fetch_token前被关闭,可能导致授权状态不匹配,间接引发后续API请求失败。
修正后的代码
import os import json import dotenv import requests import requests_oauthlib class Calendar(): def __init__(self): dotenv.load_dotenv() self.api_key = os.getenv("API_KEY") self.calendar_id = os.getenv("CALENDAR_ID") self.access_token = os.getenv("GOOGLE_CALENDAR_API_ACCESS_TOKEN") def auth(self, scopes): with open("./assets/credentials.json", "r") as json_file: credentials = json.load(json_file) client_id = credentials["web"]["client_id"] client_secret = credentials["web"]["client_secret"] redirect_uri = credentials["web"]["redirect_uris"][0] authorization_url = credentials["web"]["auth_uri"] token_url = credentials["web"]["token_uri"] # 确保fetch_token在会话有效期内执行 with requests_oauthlib.OAuth2Session(client_id=client_id, scope=scopes, redirect_uri=redirect_uri) as session: authorization_url, state = session.authorization_url(authorization_url, access_type="offline", prompt="select_account") print("点击链接授权", authorization_url) redirect_response = input("粘贴重定向URL到这里:") credentials = session.fetch_token(token_url=token_url, client_secret=client_secret, authorization_response=redirect_response) dotenv.set_key(".env", key_to_set="GOOGLE_CALENDAR_API_ACCESS_TOKEN", value_to_set=credentials["access_token"], quote_mode="never") self.access_token = credentials["access_token"] def add_event(self, summary, start_date, end_date, description="", recurrence=False): url = f"https://www.googleapis.com/calendar/v3/calendars/{self.calendar_id}/events" headers = { "Authorization": f"Bearer {self.access_token}", "Accept": "application/json", "Content-Type": "application/json" } payload = { "summary": summary, # 添加必填的summary字段 "description": description, "end": { "dateTime": end_date, "timeZone": "Asia/Taipei" }, "start": { "dateTime": start_date, "timeZone": "Asia/Taipei" } } if recurrence: payload["recurrence"] = ["RRULE:FREQ=WEEKLY"] # 使用json参数自动序列化字典为JSON格式 response = requests.post(url=url, json=payload, headers=headers) return response.text if __name__ == "__main__": c = Calendar() c.auth(["https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/calendar.events"]) # 建议使用带时区偏移的时间格式,避免解析歧义 print(c.add_event(summary="test", start_date="2024-09-05T01:00:00+08:00", end_date="2024-09-05T13:00:00+08:00"))
额外注意事项
- 时间格式优先使用带时区偏移的格式(如
2024-09-05T01:00:00+08:00),配合timeZone字段使用,减少时区解析错误。 - 确认
CALENDAR_ID为有效值(个人邮箱或共享日历ID)。 - 当前代码仅保存
access_token,建议同时保存refresh_token,用于令牌过期后自动刷新,避免重复授权。
内容的提问来源于stack exchange,提问作者高奕祥
相关产品推荐
相关产品推荐

