Google Calendar API全域委派下events.watch推送通知400错误排查
一、推送返回400错误的核心排查点
1. 路由路径不匹配(最可能的直接原因)
看你的Flask日志:POST /calendar_push HTTP/1.1,但你的路由是@app.route("/calendar-push", methods=["GET", "POST"])——这里路径里的横杠和下划线不匹配!Google是按照你创建watch时提供的address参数发送请求的,如果你watch里填的是https://xxxx.eu.ngrok.io/calendar_push,但代码里的路由是/calendar-push,就会导致请求找不到正确的处理端点,直接返回400。
先确认:
- 创建watch时的
address参数是否和Flask路由完全一致(包括大小写、横杠/下划线) - 修正路由路径,保持和watch的address一致。
2. 请求解析失败(Flask无法读取request.json)
Google Calendar的推送通知不是JSON格式,而是application/x-www-form-urlencoded的表单格式,所以你用request.json会返回None,导致Flask在返回request.json时抛出400(因为返回了空值或者不符合JSON要求的内容)。
修改你的Flask端点代码:
@app.route("/calendar-push", methods=["GET", "POST"]) def add_message(): app.logger.info("HIT THE /calendar-push ROUTE") # 改用form获取推送内容 content = request.form.to_dict() app.logger.info(content) return content, 200
这样就能正确读取Google推送的内容了,比如channel_id、resource_id这些关键信息。
3. 检查watch请求的参数完整性
创建watch时必须指定以下参数,否则可能导致推送异常:
req = my_service.events().watch( calendarId=USER_EMAIL, body={ "id": UUID, # 唯一的通道ID,比如UUID生成的字符串 "type": "web_hook", "address": f"{BASE_URL}/calendar-push", # 必须和Flask路由完全一致 "token": "可选的自定义令牌,用于验证请求来源" } ).execute()
注意:
id必须是全局唯一的,不能重复使用type必须是web_hook,不能省略address必须是公网可访问的URL(你的ngrok URL是可以的,但要确保ngrok处于运行状态)
二、关于resourceUri的403错误
这个是正常现象,resourceUri是Google内部用来追踪日历资源的地址,不需要你直接访问。Google会用自己的授权凭证去访问这个URI,你直接打开肯定会因为缺少API密钥或OAuth授权而返回403,不用理会这个问题。
三、是否需要添加Bearer Token?
不需要。Google Calendar的推送通知不需要你在watch()方法中添加Bearer Token,Google会在推送请求中带上X-Goog-Signature等头信息,用于验证请求确实来自Google(可选验证,不是强制要求)。你不需要在watch请求中添加额外的Token参数。
内容的提问来源于stack exchange,提问作者hkh

