Google API调用中的偶发/持久SSL超时错误

时间:2016-01-19 13:37:10

标签: python django google-drive-api debian

我有一个使用Python 2.7.9在Debian 8.1上运行Django 1.8.x的网站。该网站或机器不会负载过重。

网站使用“drive / v2”和“admin / directory_v1”(servicename / version)进行一些API调用。网站通常会调用files.insert,files.patch,files.move_to_trash或members.list

在过去的5-6个月里,所有人都没有问题。注意:Google于去年12月发布了“drive / v3”。大约一周前就出现了问题。

首先,我在某些(任何)API调用上遇到了一些偶发的SSL超时错误。然后我开始得到越来越多的错误。在某一点似乎是持久的,即一旦一个呼叫出现问题,那么它就会发生所有呼叫的任何呼叫。似乎没有涉及“files.move_to_trash”,除了一些零星的。

最近没有对我的网站进行任何修改。

我尝试更新“google-api-python-client”库

pip install --upgrade google-api-python-client

没有任何改进。

在接下来的几天里,我注意到持续性错误持续了几个小时,然后突然停止,所有事情都开始再次运行,几乎没有偶发错误,然后再次出现持续错误。间歇性操作。

在另一台我只用于“演示”的机器中,我得到了一些我以前从未遇到过的零星错误。

我认为非常重要的事情:我在进行API调用时会立即收到超时错误。这是一个真正的超时是很奇怪的。

我尝试的另一件事是从谷歌开发者控制台再次下载凭据JSON文件:我注意到文件中添加了一个新的密钥“project_id”(谷歌做了一些事情),无论如何都没有改变。我还试图从零重新创建凭据,重新加载JSON文件,取消关联并重新关联应用程序到谷歌驱动器,仍然没有成功。

根据谷歌支持的建议,我还检查了帐户安全设置中的“允许安全性较低的应用”已关闭。

这里有一个追溯样本:

'Traceback (most recent call last):
File ".\my_gdrive\\utils\\gdrive.py", line 130, in insert
    filee = self.GDService.service.files().insert(body = body,media_body = media_body).execute()
File "/usr/local/lib/python2.7/dist-packages/oauth2client/util.py", line 140, in positional_wrapper
    return wrapped(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/googleapiclient/http.py", line 694, in execute
    _, body = self.next_chunk(http=http, num_retries=num_retries)
File "/usr/local/lib/python2.7/dist-packages/oauth2client/util.py", line 140, in positional_wrapper
    return wrapped(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/googleapiclient/http.py", line 873, in next_chunk
    headers=headers)
File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 596, in new_request
    redirections, connection_type)
File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1609, in request
    (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1351, in _request
    (response, content) = self._conn_request(conn, request_uri, method, body, headers)
File "/usr/local/lib/python2.7/dist-packages/httplib2/__init__.py", line 1307, in _conn_request
    response = conn.getresponse()
File "/usr/lib/python2.7/httplib.py", line 1073, in getresponse
    response.begin()
File "/usr/lib/python2.7/httplib.py", line 415, in begin
    version, status, reason = self._read_status()
File "/usr/lib/python2.7/httplib.py", line 371, in _read_status
    line = self.fp.readline(_MAXLINE + 1)
File "/usr/lib/python2.7/socket.py", line 476, in readline
    data = self._sock.recv(self._rbufsize)
File "/usr/lib/python2.7/ssl.py", line 714, in recv
    return self.read(buflen)
File "/usr/lib/python2.7/ssl.py", line 608, in read
    v = self._sslobj.read(len or 1024)
SSLError: (\'The read operation timed out\',)

更新:添加了示例代码

from oauth2client.django_orm import CredentialsField
class CredentialsModel(models.Model):
    id = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True)
    credential = CredentialsField()

登录后,我会通过名为“gpermission”的视图调用una tantum来询问并向已记录的(系统)用户授予NA_GDRIVE_SCOPES权限。然后每隔几分钟就可以看到下面“THE CODE”部分中的代码。

NA_GDRIVE_SCOPES = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/admin.directory.group.member']

from django.conf import settings

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

from oauth2client import xsrfutil
from oauth2client.client import flow_from_clientsecrets
from oauth2client.django_orm import Storage

from na_gdrive.models import CredentialsModel

def gdrive_get_credentials(func):

    def decorator(request, *args, **kwargs):

        storage = Storage(CredentialsModel, 'id', request.user, 'credential')
        credential = storage.get()
        if credential is None or credential.invalid:

            # settings.NA_GDRIVE_CLIENT_SECRETS_PATH, name of a file containing the OAuth 2.0 information for this
            # application, including client_id and client_secret, which are found
            # on the API Access tab on the Google APIs
            # Console <http://code.google.com/apis/console>

            FLOW = flow_from_clientsecrets(settings.NA_GDRIVE_CLIENT_SECRETS_PATH,
                                           scope = settings.NA_GDRIVE_SCOPES,
                                           redirect_uri = urlparse.urljoin(settings.DOMAIN_ONLINE, reverse("gdrive_auth_return")))

            FLOW.params['access_type'] = 'offline'
            FLOW.params['approval_prompt'] = 'force' 
            FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY, request.user) + defs.NA_GDRIVE_AUTHNEXT_SEP + request.GET.get("next", reverse("index"))

            authorize_url = FLOW.step1_get_authorize_url()

            return HttpResponseRedirect(authorize_url)

        return func(request, storage, credential, *args, **kwargs)

    return decorator

######## THE VIEWS ########

@login_required
def auth_return(request): #mapped on reverse("gdrive_auth_return")
    if not xsrfutil.validate_token(settings.SECRET_KEY,
                                   str(request.GET['state'].split(defs.NA_GDRIVE_AUTHNEXT_SEP)[0]), #http://stackoverflow.com/questions/27441567/django-1-7-google-oauth2-token-validation-failure
                                   request.user):
        return HttpResponseBadRequest()

    FLOW = flow_from_clientsecrets(settings.NA_GDRIVE_CLIENT_SECRETS_PATH,
                                   scope = settings.NA_GDRIVE_SCOPES,
                                   redirect_uri = urlparse.urljoin(settings.DOMINIO_ONLINE, reverse("gdrive_auth_return")))

    FLOW.params['access_type'] = 'offline'
    FLOW.params['approval_prompt'] = 'force' #Questa non dovrebbe essere necessaria ma al momento è così che sta funzionando in primaindustria dopo i grossi problemi avuti con google

    credential = FLOW.step2_exchange(request.REQUEST)
    storage = Storage(CredentialsModel, 'id', request.user, 'credential')
    storage.put(credential)

    r_uri = request.GET['state'].split(defs.NA_GDRIVE_AUTHNEXT_SEP)[1]
    return HttpResponseRedirect(r_uri)

#The view I call una tantum to ask/grant permission the first time
#when logged with User.objects.get(email = defs.GDRIVE_SYSTEMUSER_EMAIL)

@login_required
@gdrive_get_credentials
def gpermission(request, storage, credential):
    return HttpResponse("Permissions granted")

######## THE CODE ########

from apiclient.discovery import build
from apiclient import errors
from apiclient import http

user = User.objects.get(email = defs.GDRIVE_SYSTEMUSER_EMAIL)
storage = Storage(CredentialsModel, 'id', user, 'credential')
credential = storage.get()
if credential is None or credential.invalid is True:
    raise Exception, 'Bad GDrive credentials'

httpobj = credential.authorize(httplib2.Http())
service = build("drive", "v2", http = httpobj)

media_body = MediaFileUpload(filename, mimetype = mime_type, resumable = True)
body = {
    'title': title,
    'description': description,
    'mimeType': mime_type,
    'parents' : parents_id
}

try:
    filee = service.files().insert(body = body, media_body = media_body).execute() #This gets time SSL Timeout Error
    return filee
except errors.HttpError, error:
    print 'An error occured: %s' % error
    raise

更新:添加额外信息

在最后几天,我打开了一个python shell,在那里我用storage.get()读取了凭证对象(只有一次)。如果我在获取持久性错误时从shell(仍然打开)将文件提交到谷歌驱动器上,我没有任何问题。

0 个答案:

没有答案