使用API令牌从私有BitBucket仓库下载文件内容时遇令牌无效类错误的问题排查
首先,我帮你梳理下代码和测试环节里的几个关键问题,这些大概率是导致你遇到"令牌无效"错误的原因:
1. Accept 请求头设置错误,导致请求端点行为不符合预期
你的download_raw_file_from_bitbucket函数里,把Accept头设为了application/json,这个配置会让BitBucket API返回文件的元数据JSON结构,而不是你需要的原始文件内容。更关键的是,这个头的设置会让API的权限校验逻辑出现误判,进而返回令牌相关的错误提示。
如果你的目标是获取文件的原始文本,需要把Accept头改成BitBucket专门用于返回原始内容的MIME类型:
headers = { "Authorization": f"Bearer {BITBUCKET_API_TOKEN}", "Accept": "application/vnd.bitbucket.raw" }
同时,你代码里后续尝试用json.loads解析返回内容的逻辑也可以去掉了,因为现在API会直接返回文件的原始文本。
2. 测试用的cURL请求URL格式完全错误
你写的测试cURL请求URL缺少了BitBucket API要求的核心路径部分:
# 你当前错误的cURL URL curl -H "Authorization: Bearer <my token goes here>" -H "Accept: application/json" "https://api.bitbucket.org/2.0/repositories/<user>/<repo>/<folder>/<folder>/<folder>/<folder>/<file.extension>"
正确的URL必须包含/src/{ref}/段(ref是分支名、标签名或提交哈希),应该和你代码里构造的URL结构一致:
# 修正后的cURL示例 curl -H "Authorization: Bearer <your-token>" -H "Accept: application/vnd.bitbucket.raw" "https://api.bitbucket.org/2.0/repositories/<workspace>/<repo_slug>/src/<branch-or-commit>/<file-path>"
错误的URL路径会触发API的权限校验逻辑误判,直接返回令牌无效类的错误提示。
3. 令牌类型与Authorization头不匹配的隐藏坑
虽然你假设令牌权限正确,但要注意BitBucket的两种令牌类型对应不同的认证方式:
- 个人访问令牌(PAT):用你代码里的
Bearer {token}格式是正确的 - 应用密码(App Password):需要用Basic认证,格式为
Basic {base64编码的"用户名:应用密码"},不能用Bearer头
如果你实际创建的是应用密码而非个人访问令牌,哪怕权限设置正确,也会返回令牌无效的错误。
4. URL解析函数的小瑕疵(影响可读性与后续维护)
你的_parse_bitbucket_url函数里,把解析出的commit字段赋值给了返回字典的branch键,但实际上这个字段可以是分支、标签或提交哈希,更准确的命名应该是ref,符合BitBucket API的术语规范,避免后续混淆:
return { "workspace": workspace, "repo_slug": repo_slug, "ref": commit, # 重命名为ref更准确 "path": file_path }
对应的API URL构造部分也要改成parsed['ref']。
修正后的完整下载函数示例
async def download_raw_file_from_bitbucket(config: RunConfigurator, url: str) -> Optional[str]: BITBUCKET_API_TOKEN = KeyManager(getattr(config, 'api_keys', {})).get_key("BITBUCKET_API_TOKEN") parsed = _parse_bitbucket_url(url) api_url = ( f"https://api.bitbucket.org/2.0/repositories/" f"{parsed['workspace']}/{parsed['repo_slug']}/src/" f"{parsed['ref']}/{parsed['path']}" ) headers = { "Authorization": f"Bearer {BITBUCKET_API_TOKEN}", "Accept": "application/vnd.bitbucket.raw" } async with aiohttp.ClientSession() as session: async with session.get(api_url, headers=headers, allow_redirects=True) as response: if not response.ok: raise Exception(f"{response.status} {await response.text()}") return await response.text()
内容来源于stack exchange

