传入有效Token时google.oauth2.credentials.Credentials调用YouTube API失败排查
我看了你遇到的情况:你已经用curl成功调用YouTube Channels API拿到了自己的频道数据,但换成Google官方的Python库实现时,却出现了和没传Access Token一样的authorizationRequired错误,而且你确认自己的Access Token和API Key都是有效的——这情况我之前也碰到过,问题出在Python客户端库的参数优先级上!
问题根源
当你在build方法里**同时传入credentials(带Access Token)和developerKey**时,Google的Python客户端库会优先使用developerKey发起请求,直接忽略掉credentials里的Access Token。这就导致你的请求根本没带上Authorization: Bearer xxx头,和你手动去掉curl里的Authorization头效果一样,自然触发了401授权错误。
解决办法
最简单的修复就是去掉build方法里的developerKey参数,因为当你使用OAuth2的Credentials(也就是你的Access Token)进行用户身份验证时,不需要再传入API Key——API Key主要用于不需要用户身份的公开数据请求,而mine=true的请求必须依赖用户授权的Access Token。
修改后的get_authenticated_service函数应该是这样:
def get_authenticated_service(options): creds = google.oauth2.credentials.Credentials(options.access_token) # 移除了developerKey参数 return build('youtube', 'v3', credentials=creds)
补充:如果确实需要用到API Key的场景
如果之后你有需要同时结合API Key和OAuth授权的请求(比如某些特殊的混合权限接口),可以不在build里传developerKey,而是在具体的请求方法里手动添加key参数,比如:
request = youtube.channels().list(part="snippet", mine=True, key=options.api_key)
不过对于你当前的mine=true请求,完全不需要API Key,只需要保证Credentials被正确使用就够了。
修改后的完整代码
import argparse import google.oauth2.credentials from googleapiclient.discovery import build from googleapiclient.errors import HttpError def get_authenticated_service(options): creds = google.oauth2.credentials.Credentials(options.access_token) return build('youtube', 'v3', credentials=creds) def list_channels(youtube, options): request = youtube.channels().list(part="snippet", mine=True) response = request.execute() print(response) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--api_key', required=True) parser.add_argument('--access_token', required=True) args = parser.parse_args() youtube = get_authenticated_service(args) try: list_channels(youtube, args) except HttpError as e: print('An HTTP error {0} occurred:\n{1}'.format(e.resp.status, e.content))
(注:虽然--api_key参数还在,但代码里已经不用它了,如果你确定之后也用不上,可以把这个参数删掉)
最后运行原来的命令就能正常拿到频道数据啦!
内容的提问来源于stack exchange,提问作者Sagi Mann

