Google 的 API 通过 python 的长期超时问题?

Chronic timeout issue with Google's API via python?

我正在开发一个小网络应用程序来帮助我管理我的 gmail。我已经通过 Google 的 API 使用以下功能使用我通过 django-allauth 收到的 OAuth 令牌对其进行了设置。

import google.oauth2.credentials
from .choices import GMAIL
from allauth.socialaccount.models import SocialToken, SocialAccount
from apiclient.discovery import build


def get_credentials(user):
    account = SocialAccount.objects.get(user=user.id)
    token = SocialToken.objects.get(app=GMAIL, account=account).token
    credentials = google.oauth2.credentials.Credentials(token)
    service = build('gmail', 'v1', credentials=credentials)
    return service

这似乎有时有效,但不幸的是,它不是很可靠。它在 build() 函数中经常超时,只有大约三分之一的时间会成功。我想知道是什么导致了这种行为,是否有更可靠的方法来访问 API?

我从 these docs 中找到了以下 AuthorizedSession class:

from google.auth.transport.requests import AuthorizedSession

authed_session = AuthorizedSession(credentials)

response = authed_session.request(
    'GET', 'https://www.googleapis.com/storage/v1/b')

但我不知道如何将它变成与 Google 一起使用的那种对象 API:

def get_labels(user):
    service = get_credentials(user)
    results = service.users().labels().list(userId='me').execute()
    labels = results.get('labels', [])
    return labels

不幸的是,Google's docs 建议使用我希望避免的已弃用的软件包。

这是我第一次真正使用 OAuth 强制 API。有人有什么建议吗?

编辑:我在我的 Macbook 上尝试后发布。我也在我的 Windows 机器上试过了,它工作得更稳定,但每次只需要大约 20 秒就可以完成 build()。我觉得我做错了什么。

在我最终将刷新令牌添加到组合中后,今天早上效果好多了。也许它的缺席导致了另一端的一些问题。我会继续测试,但现在一切正常:

这是我的完整解决方案:

import google.oauth2.credentials
from google.auth.transport.requests import Request

from apiclient import errors, discovery

from myproject.settings import GMAIL_CLIENT_API_KEY, GMAIL_CLIENT_API_SECRET


def get_credentials(user):
    token_set = user.socialaccount_set.first().socialtoken_set.first()
    token = token_set.token
    refresh_token = token_set.token_secret
    credentials = google.oauth2.credentials.Credentials(
        token,
        refresh_token=refresh_token,
        client_id=GMAIL_CLIENT_API_KEY,
        client_secret=GMAIL_CLIENT_API_SECRET,
        token_uri= google.oauth2.credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT,
    )

    if credentials.expired:
        request = Request()
        credentials.refresh(request)

    service = discovery.build('gmail', 'v1', credentials=credentials)
    return service

如您所见,我将 API 密钥添加到我的设置文件中并在此处引用它们。昨天我在查看源文件时偶然发现了 token_urirefresh_token 是找到时间最长的一块。

好消息是 django-allauth 会将刷新令牌保存到 token_secret 列下的 SocialToken 模型。但是,只有在您的设置中包含以下内容时才会执行此操作:

SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'SCOPE': [
            'profile',
            'email',
            'https://www.googleapis.com/auth/gmail.labels',
            'https://www.googleapis.com/auth/gmail.modify'
        ],
        'AUTH_PARAMS': {
            'access_type': 'offline',
        }
    }
}

具体来说,AUTH_PARAMS中的access_type必须设置为'offline'according to the docs

现在,如果您在实施此更改之前连接了您的帐户,这仍然会给您带来麻烦,因此您还需要通过 Google permissions to obtain a new refresh token. More about that can be found in this question.

撤销对您的应用程序的访问权限

我不确定这是否是 proper/intended 执行此操作的方法,但在 Google 更新他们的 Django 文档之前,此方法至少应该可以用于测试目的。