Python请求Tado API返回403但PowerShell请求正常,求解决
查了大量故障排查资料仍未解决,这是第二次尝试,已做深入排查。参考Tado的API文档编写了Python代码,调用/schedule/activeTimeTable接口返回403,但调用同域下的/details接口返回200;而用PowerShell的Invoke-WebRequest调用同一个/schedule/activeTimeTable接口却能成功返回200。
代码与请求详情
Python代码
import requests import json url1 = "https://my.tado.com/api/v2/homes/[myzone]/zones/2/schedule/activeTimeTable" url2 = "https://my.tado.com/api/v2/homes/[myzone]/zones/2/details" token = "[mytoken]" headers = { 'Authorization': "Bearer "+token } data1 = {"id": 1} data2 = {"name": "Eetkamer"} timeout = 15 r1 = requests.put(url1, headers=headers, json=data1, timeout=timeout) r2 = requests.put(url2, headers=headers, json=data2, timeout=timeout) print("###################") print(r1) print("###################") print(r2) print("###################")
执行结果:r1返回<Response [403]>,r2返回<Response [200]>
PowerShell请求详情
PS C:\Git\requests-set-schedule-tado> Invoke-WebRequest -UseBasicParsing -Uri "https://my.tado.com/api/v2/homes/[myzone]/zones/2/schedule/activeTimetable" ` >> -Method "PUT" ` >> -WebSession $session ` >> -Headers @{ >> "accept"="application/json" >> "authorization"="Bearer [mytoken]" >> } ` >> -ContentType "application/json" ` >> -Body "{`"id`":1}"
执行结果:返回StatusCode: 200,响应内容正常。
问题分析与解决方案
对比Python和PowerShell的请求,核心差异有三点,逐一修正即可解决:
URL路径拼写不一致
Python代码中URL路径是activeTimeTable(大写T),而PowerShell中是activeTimetable(小写t)。API路径区分大小写,拼写错误会导致资源找不到或权限验证失败,先修正URL拼写。缺失
Accept请求头
PowerShell显式设置了accept: application/json,而Python的requests库默认的Accept头是*/*。部分API会验证该头,要求明确接受JSON格式响应,需在Python请求头中添加该字段。未使用会话保持Cookie
PowerShell使用-WebSession $session复用了之前登录的会话Cookie(如CSRF Token、Session ID等),而Python的请求是独立的,未携带这些Cookie。Tado API可能会验证会话完整性,缺失Cookie会返回403,需用requests.Session()保持会话。
修改后的Python代码
import requests # 创建会话,模拟PowerShell的WebSession session = requests.Session() token = "[mytoken]" # 对齐PowerShell的请求头 headers = { 'Authorization': f"Bearer {token}", 'Accept': 'application/json', 'Content-Type': 'application/json' } # 修正URL路径的大小写 url1 = "https://my.tado.com/api/v2/homes/[myzone]/zones/2/schedule/activeTimetable" url2 = "https://my.tado.com/api/v2/homes/[myzone]/zones/2/details" data1 = {"id": 1} data2 = {"name": "Eetkamer"} timeout = 15 # 使用会话发送请求 r1 = session.put(url1, headers=headers, json=data1, timeout=timeout) r2 = session.put(url2, headers=headers, json=data2, timeout=timeout) print("###################") print(r1.status_code, r1.text) print("###################") print(r2.status_code, r2.text) print("###################")
额外排查建议
如果仍未解决,可打印Python发送的请求头,和PowerShell的请求头做对比,补充缺失的字段:
print("Python请求头:", r1.request.headers)
内容的提问来源于stack exchange,提问作者ErikDB

