使用元组式认证调用GitHub API返回空数据的原因排查
问题分析与解决
代码示例
query = "https://api.github.com/repos/rhinstaller/anaconda/tags" response = requests.get(query,auth=(self.username,self.token)) response.raise_for_status() # raises exception when not a 2xx if response.status_code != 204: try: data = response.json() print("data = ",data) except: print("0")
问题描述
上述代码始终返回空data,但使用response = requests.get(query)无认证调用时,在触发限流前均可正常工作。此前Python中这种元组式认证调用GitHub API是正常的,请问导致该问题的原因是什么?
补充信息
执行print(response.__dict__)得到如下结果:
{'_content': b'{"message":"Bad credentials","documentation_url":"https://docs.github.com/rest"}', '_content_consumed': True, '_next': None, 'status_code': 401, 'headers': {'Server': 'GitHub.com', 'Date': 'Sat, 22 Oct 2022 14:01:13 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '80', 'X-GitHub-Media-Type': 'github.v3; format=json', 'X-RateLimit-Limit': '60', 'X-RateLimit-Remaining': '56', 'X-RateLimit-Reset': '1666449620', 'X-RateLimit-Used': '4', 'X-RateLimit-Resource': 'core', 'Access-Control-Expose-Headers': 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset', 'Access-Control-Allow-Origin': '*', 'Strict-Transport-Security': 'max-age=31536000; includeSubdomains; preload', 'X-Frame-Options': 'deny', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '0', 'Referrer-Policy': 'origin-when-cross-origin, strict-origin-when-cross-origin', 'Content-Security-Policy': "default-src 'none'", 'Vary': 'Accept-Encoding, Accept, X-Requested-With', 'X-GitHub-Request-Id': 'D2F0:13300:1D277E2:1D98791:6353F7A9'}, 'raw': <urllib3.response.HTTPResponse object at 0x7f596e77da90>, 'url': 'https://api.github.com/repos/rhinstaller/anaconda/tags', 'encoding': 'utf-8', 'history': [], 'reason': 'Unauthorized', 'cookies': <RequestsCookieJar[]>, 'elapsed': datetime.timedelta(microseconds=176914), 'request': <PreparedRequest [GET]>, 'connection': <requests.adapters.HTTPAdapter object at 0x7f596e76cbd0>}
原因与解决方案
从补充信息的_content字段能明确看到,GitHub返回了"Bad credentials"(凭据无效)错误,状态码为401(未授权),核心问题是认证方式不匹配:
- 元组式auth的本质是Basic Auth:当你用
auth=(username, token)时,requests会自动封装成Basic Auth请求,但GitHub的Basic Auth要求「用户名+密码」,而你传入的是「用户名+个人访问令牌(PAT)」,直接导致认证失败。 - 代码逻辑的隐藏问题:
response.raise_for_status()遇到401这类非2xx状态码时会直接抛出异常,后续解析data的代码根本不会执行,你看到的空data是异常抛出前的无效输出;同时代码里if语句的缩进错误,也会引发语法问题。
正确的认证方式
方式一:使用Bearer Token请求头(推荐)
GitHub API更推荐直接将PAT放在Authorization头里:
headers = {"Authorization": f"token {self.token}"} response = requests.get(query, headers=headers)
方式二:使用HTTPBasicAuth(兼容写法)
如果要继续用auth参数,需明确使用HTTPBasicAuth,此时用户名可填任意值(比如你的GitHub用户名或空字符串),密码填PAT即可:
from requests.auth import HTTPBasicAuth response = requests.get(query, auth=HTTPBasicAuth(self.username, self.token))
代码修复建议
同时修正缩进问题,并添加异常捕获避免程序直接崩溃:
query = "https://api.github.com/repos/rhinstaller/anaconda/tags" headers = {"Authorization": f"token {self.token}"} try: response = requests.get(query, headers=headers) response.raise_for_status() if response.status_code != 204: data = response.json() print("data = ", data) except requests.exceptions.HTTPError as e: print(f"请求错误: {e}") print(f"返回内容: {response.text}") except Exception as e: print(f"解析错误: {e}")
内容的提问来源于stack exchange,提问作者PHV
相关产品推荐
相关产品推荐

