You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Google Calendar API持续返回400 Bad Request问题求助

解决Google Calendar API添加事件返回400 Bad Request的问题

问题根源分析

你的代码存在三个关键错误,直接导致了400请求失败:

  1. 请求体格式不匹配
    调用requests.post时使用data=payload会把字典编码为表单数据(application/x-www-form-urlencoded),但你在请求头里声明了Content-Type: application/json,API无法解析格式不匹配的请求体。

  2. 缺少必填的summary字段
    你调用add_event时传入了summary参数,但代码里没有将其加入请求的payload中。Google Calendar API创建事件时summary是必填项,缺失会直接触发400错误。

  3. 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,提问作者高奕祥

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:30:16