调用Graph API扫描SharePoint目录脚本停滞,疑Bearer Token过期
问题分析与解决方案
核心结论
大概率是Bearer Token过期导致的,而你没收到错误提示,是因为代码完全没有处理请求失败的场景。
原因说明
- Token过期的必然性:Microsoft Graph的访问令牌(access_token)默认有效期就是1小时,刚好和你脚本停止输出的时间点吻合。当令牌过期后,Graph API会返回
401 Unauthorized状态码,但你的代码完全没处理这类错误响应。 - 无错误提示的根源:
- 你的代码只判断了响应JSON中是否存在
value字段,但令牌过期时的响应里根本没有value,代码会直接跳过文件遍历逻辑。 - 代码没有检查HTTP响应状态码,也没有捕获请求过程中可能出现的异常(比如连接超时、JSON解析失败)。如果请求因为令牌过期返回401,或者网络问题卡住,脚本会静默停在那里,不会输出任何错误信息。
- 你的代码只判断了响应JSON中是否存在
代码修复建议
以下是针对问题的修复版本,添加了令牌刷新、错误处理和超时设置:
import requests import time from requests.exceptions import RequestException # 替换为你的OAuth2配置(使用刷新令牌机制) CLIENT_ID = "你的客户端ID" CLIENT_SECRET = "你的客户端密钥" REFRESH_TOKEN = "你的刷新令牌" TOKEN_URL = "https://login.microsoftonline.com/你的租户ID/oauth2/v2.0/token" def get_new_access_token(): """使用刷新令牌获取新的访问令牌""" payload = { "grant_type": "refresh_token", "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "refresh_token": REFRESH_TOKEN } response = requests.post(TOKEN_URL, data=payload) response.raise_for_status() token_data = response.json() return token_data["access_token"], token_data["expires_in"] # 初始化令牌 access_token, expires_in = get_new_access_token() # 记录令牌过期时间(提前5分钟刷新) expire_time = time.time() + expires_in - 300 headers = {"Authorization": f"Bearer {access_token}"} url = "[URL TO THE SHAREPOINT]" consentfilecount = 0 clientreportcount = 0 graphlinkcount = 0 while True: # 检查令牌是否即将过期,提前刷新 if time.time() >= expire_time: access_token, expires_in = get_new_access_token() expire_time = time.time() + expires_in - 300 headers = {"Authorization": f"Bearer {access_token}"} try: # 添加超时设置,避免无限等待 graph_result = requests.get(url=url, headers=headers, timeout=30) # 主动抛出HTTP错误(比如401、500等) graph_result.raise_for_status() response_json = graph_result.json() if "value" in response_json: for item in response_json["value"]: # 避免使用Python内置类型名作为变量名 item_name = item["name"].lower() if "client consent form" in item_name: consentfilecount += 1 print(item["name"]) if "final client report" in item_name: clientreportcount += 1 print(item["name"]) if "@odata.nextLink" in response_json: url = response_json["@odata.nextLink"] graphlinkcount += 1 else: break except RequestException as e: print(f"请求出错: {str(e)}") break except ValueError as e: print(f"JSON解析失败: {str(e)}") break print(f"Client Consent Form数量: {consentfilecount}") print(f"Final Client Report数量: {clientreportcount}")
关键修复点
- 令牌自动刷新:使用刷新令牌(refresh_token)定期获取新的访问令牌,彻底解决1小时过期问题。
- 错误处理:通过
raise_for_status()捕获HTTP错误,添加try-except块处理请求和解析异常,确保错误能被及时打印。 - 超时设置:给
requests.get添加timeout参数,防止请求因网络问题无限挂起。 - 变量规范:避免使用
list这类Python内置类型名作为变量,避免潜在的语法冲突。
内容的提问来源于stack exchange,提问作者WhoamI
相关产品推荐
相关产品推荐

