2小时后Google Drive Python API可恢复上传错误401

Posted

技术标签:

【中文标题】2小时后Google Drive Python API可恢复上传错误401【英文标题】:Google Drive Python API resumable upload error 401 after 2 hours 【发布时间】:2012-12-26 12:30:58 【问题描述】:

首先,如果这是一个太愚蠢的问题,我很抱歉......这是我第一次尝试使用此脚本中涉及的任何技术(Python、驱动器 api、oauth 2.0、等等)。我发誓在发布问题之前我已经搜索并尝试了大约一周。呵呵

我正在尝试使用 google-api-python-client 上传一个仅在 Linux Debian 终端上的大文件 (3.5GiB)。我在上传小文件方面取得了一些成功,但是当我尝试上传大文件时,上传会在 HTTP 401 错误(未经授权)开始后大约 1~2 小时停止。我一直在寻找如何获得新的访问令牌,但收效甚微。

这是我目前的(更新)代码:

#!/usr/bin/python

import httplib2
import pprint
import time

from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from apiclient import errors
from oauth2client.client import OAuth2WebServerFlow

# Copy your credentials from the APIs Console
CLIENT_ID = 'myclientid'
CLIENT_SECRET = 'myclientsecret'

# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'

# Redirect URI for installed apps
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'

# Run through the OAuth flow and retrieve credentials
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI)
authorize_url = flow.step1_get_authorize_url()
print 'Go to the following link in your browser: ' + authorize_url
code = raw_input('Enter verification code: ').strip()
credentials = flow.step2_exchange(code)

# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = credentials.authorize(http)

drive_service = build('drive', 'v2', http=http)

# Insert a file
media_body = MediaFileUpload('bigfile.zip', mimetype='application/octet-stream', chunksize=1024*256, resumable=True)
body = 
    'title': 'bigfile.zip',
    'description': 'Big File',
    'mimeType': 'application/octet-stream'


retries = 0
request = drive_service.files().insert(body=body, media_body=media_body)
response = None
while response is None:
    try:
            print http.request.credentials.access_token
            status, response = request.next_chunk()
            if status:
                    print "Uploaded %.2f%%" % (status.progress() * 100)
                    retries = 0
    except errors.HttpError, e:
            if e.resp.status == 404:
                    print "Error 404! Aborting."
                    exit()
            else:   
                    if retries > 10:
                            print "Retries limit exceeded! Aborting."
                            exit()
                    else:   
                            retries += 1
                            time.sleep(2**retries)
                            print "Error (%d)... retrying." % e.resp.status
                            continue
print "Upload Complete!"

经过一番挖掘,我发现授权的http对象在收到401后会自动刷新访问令牌。虽然确实改变了访问令牌,但仍然没有按预期继续上传...见下面的输出:

ya29.AHES6ZTo_-0oDqwn3JnU2uCR2bRjpRGP0CSQSMHGr6KvgEE
Uploaded 2.28%
ya29.AHES6ZTo_-0oDqwn3JnU2uCR2bRjpRGP0CSQSMHGr6KvgEE
Uploaded 2.29%
ya29.AHES6ZTo_-0oDqwn3JnU2uCR2bRjpRGP0CSQSMHGr6KvgEE
Uploaded 2.29%
ya29.AHES6ZTo_-0oDqwn3JnU2uCR2bRjpRGP0CSQSMHGr6KvgEE
Uploaded 2.30%
ya29.AHES6ZTo_-0oDqwn3JnU2uCR2bRjpRGP0CSQSMHGr6KvgEE
Error (401)... retrying.
ya29.AHES6ZQqp3_qbWsTk4yVDdHnlwc_7GvPZiFIReDnhIIiHao
Error (401)... retrying.
ya29.AHES6ZSqx90ZOUKqDEP4AAfWCVgXZYT2vJAiLwKDRu87JOs
Error (401)... retrying.
ya29.AHES6ZTp0RZ6U5K5UdDom0gq3XHnyVS-2sVU9hILOrG4o3Y
Error (401)... retrying.
ya29.AHES6ZSR-IOiwJ_p_Dm-OnCanVIVhCZLs7H_pYLMGIap8W0
Error (401)... retrying.
ya29.AHES6ZRnmM-YIZj4S8gvYBgC1M8oYy4Hv5VlcwRqgnZCOCE
Error (401)... retrying.
ya29.AHES6ZSF7Q7C3WQYuPAWrxvqbTRsipaVKhv_TfrD_gef1DE
Error (401)... retrying.
ya29.AHES6ZTsGzwIIprpPhCrqmoS3UkPsRzst5YHqL-zXJmz6Ak
Error (401)... retrying.
ya29.AHES6ZSS_1ZBiQJvZG_7t5uW3alsy1piGe4-u2YDnwycVrI
Error (401)... retrying.
ya29.AHES6ZTLFbBS8mSFWQ9zK8cgbX8RPeLghPxkfiKY54hBB-0
Error (401)... retrying.
ya29.AHES6ZQBeMWY50z6fWXvaCcd5_AJr_AYOuL2aiNKpK-mmyU
Error (401)... retrying.
ya29.AHES6ZTs2mYYSEyOqI_Ms4itKDx36t39Oc5RNZHkV4Dq49c
Retries limit exceeded! Aborting.

我正在使用安装了 Python 2.5.2 的 debian lenny,大约一周前通过 pip install 安装了 ssl 和 google-api-python-client。

提前感谢您的帮助。

编辑:显然,问题不在于 api。我尝试了上面相同的代码,但是有两个小文件,它们之间有 1h (system.sleep())。输出是:

ya29.AHES6ZRUssiLfuhqCP9Cu7C7LuhRV2rYzPldU27wiMJZWb8
Uploaded 66.89%
ya29.AHES6ZRUssiLfuhqCP9Cu7C7LuhRV2rYzPldU27wiMJZWb8
Upload 1 Complete!
ya29.AHES6ZRUssiLfuhqCP9Cu7C7LuhRV2rYzPldU27wiMJZWb8
Uploaded 57.62%
ya29.AHES6ZQd3o1ciwXpNFImH3CK0-dJAtQba_oeIO9DDbIq154
Upload 2 Complete!

对于第二次上传,成功使用了新的访问令牌。那么,也许可恢复会话会在一段时间后过期,或者仅对特定的访问令牌有效?

【问题讨论】:

根据credentials.authorize 上的文档,我认为 http.request 对象应该在收到 401 时自动刷新访问令牌。我会做一些调试,看看是否真的发生了。 我确认了。即使我什么都不做刷新访问令牌,API 在收到 401 后也会刷新(我打印了 http.request.credentials.access_token 并且在第一个 401 之后它会自动更改)。但它不起作用......也许是一个错误? 另一个更新:我尝试通过简单上传(resumable = False)上传文件,但收到有关文件大小的错误:“OverflowError: long int too large to convert to int” 【参考方案1】:

我认为问题是在 1-2 小时限制后,您对远程数据库的访问令牌过期;切断与远程服务器的连接。我认为您可以做的是查看您的主机 API 手册...他们应该在其中包含有关“刷新令牌”的内容(他们为您提供了另一个访问令牌,请注意,某些主机仅允许您在每个会话中使用一个刷新令牌),如果他们被允许无限量,您可以使用计时器和 AJAX 的组合来继续要求更多的访问令牌。

如果没有,那么您将需要一个 AJAX 请求以获取另一个授权令牌,并每小时将其交换为另一个访问令牌。这听起来像是一个非常严格的过程,但我认为这是您的令牌持续过期的唯一方法。

另外,您是否尝试过其他上传方法?如果你说上面的脚本运行了 1-2 个小时,它只上传了 1.44% 的文件,这可能需要 100 多个小时才能完全上传(对于只有 3 Gigs 来说太长了)。

【讨论】:

嗨,德文郡。感谢您的快速答复。我怀疑问题实际上是访问令牌过期。我尝试使用Credentials.refresh 函数对其进行更新,但无法使其正常工作。请参阅异常 401 处理。该手册讨论了访问(过期)和刷新令牌(永不过期),但我没有找到实现访问令牌更新的方法。至于上传时间,我所在城市的平均上传速度是正常的(128kbps ~ 256kbps)。 @user1970843:我不确定您的特定服务器主机的文档是什么以获得刷新密钥,所以很遗憾,我无法为您提供特定于他们要求的代码。但据我所知,只要您的会话正在运行,刷新令牌就不会过期,但大多数主机只允许您使用一次......您是否可以使用 AJAX 只需复制您获取身份验证令牌的第一个过程和交换访问令牌;因为如果这是一个函数,您可以使用 AJAX 每隔一小时左右重新运行该函数。 我对 AJAX 不是很熟悉,但这不就是一种网站技术吗?我的是一个本地 python 脚本,我看不出 AJAX 会在哪里应用。我尝试在第一个 401 之后再次重复身份验证过程(包括访问网站以获取新的访问代码),仍然没有成功。 @user1970843:哦,对不起,我误会了,因为您使用的是 API,所以我认为它是一个基于 Web 的平台,但现在我明白了。无论哪种方式,你都可以用 python 做同样的事情;这是相同的想法,只是不同的语言脚本。我想我对正在发生的事情有一个可能的想法;可能您的访问令牌最终过期,但服务器仍在寻找刷新相同的令牌但找不到它。也许有一些方法可以保持相同的令牌值并使用相同的值更新您的令牌,或者每隔一小时检查它何时到期。 但是 API 不检查令牌过期时间......我刚刚发现它尝试(自动)在从服务器接收到 401 后使用刷新令牌获取新的访问令牌,这意味着(我猜)令牌在服务器端过期。【参考方案2】:

我提交了一个issue on the google-api-python-client project,据 google 的 Joe Gregorio 说,问题出在后端:

“这是后端的问题,而不是 API 或您的代码的问题。正如您推断的那样,如果上传时间过长,access_token 就会过期,此时无法继续可恢复的上传。有工作目前正在修复此问题,一旦问题在服务器端得到修复,我将更新此错误。”

【讨论】:

而且过了半年还需要解决。有谁知道任何解决方法? Joe Gregorio 说 2 天前问题已解决。 运气不好。 401 大约 1 小时后仍然停止。我仍然相信我会“庆祝”这个 bug 的生日。呵呵 蛋糕有人送来了吗?小虫子的第一个生日是今天!不过我最近没有测试它……很久以前就放弃了。 这个错误已经被修复了。

以上是关于2小时后Google Drive Python API可恢复上传错误401的主要内容,如果未能解决你的问题,请参考以下文章

Google Drive API v3 Python文件中缺少某些文件()。list()

Google Drive API Python 服务帐户示例

将 Google Drive 挂载到 Python Colab 错误

Python,pandas.read_csv 来自 Google Drive 文件的 1000 万行大型 csv 文件

Python:从 Google Drive API 获取 zip 文件并加载其内容

google-drive-ocamlfuse挂载后文件夹问号?不能访问