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

调用Graph API扫描SharePoint目录脚本停滞,疑Bearer Token过期

问题分析与解决方案

核心结论

大概率是Bearer Token过期导致的,而你没收到错误提示,是因为代码完全没有处理请求失败的场景。

原因说明

  1. Token过期的必然性:Microsoft Graph的访问令牌(access_token)默认有效期就是1小时,刚好和你脚本停止输出的时间点吻合。当令牌过期后,Graph API会返回401 Unauthorized状态码,但你的代码完全没处理这类错误响应。
  2. 无错误提示的根源:
    • 你的代码只判断了响应JSON中是否存在value字段,但令牌过期时的响应里根本没有value,代码会直接跳过文件遍历逻辑。
    • 代码没有检查HTTP响应状态码,也没有捕获请求过程中可能出现的异常(比如连接超时、JSON解析失败)。如果请求因为令牌过期返回401,或者网络问题卡住,脚本会静默停在那里,不会输出任何错误信息。

代码修复建议

以下是针对问题的修复版本,添加了令牌刷新、错误处理和超时设置:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 00:56:25