我正在尝试从GAE应用程序创建Dropbox.com文件夹中的文件。 我已经完成了注册Dropbox应用程序的所有步骤,并在我的开发机器上本地安装了Dropbox本地的Python SDK。 (请参阅dropbox.com API)。 当我在本地计算机上的dropbox SDK中使用cli_client.py测试脚本访问dropbox时,它完全可以正常工作 - 可以'放'文件等。
我现在想开始在GAE环境中工作,所以事情变得有点棘手。 一些帮助会很有用。
对于那些熟悉Dropbox API代码的人,到目前为止我遇到了以下问题:
第1期
rest.py Dropbox API模块使用pkg_resources来获取本地计算机安装的site-packages中安装的证书。 我换了
TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')
与
TRUSTED_CERT_FILE = file('trusted-certs.crt')
并将cert文件放在我的GAE应用程序目录中。也许这不太对劲;请参阅下面的我的身份验证错误代码。
第2期
session.py Dropbox API模块使用 oauth 模块,因此我将include更改为appengine oauth。
但提出了一个例外,即GAE的oauth没有Dropbox session.py模块使用的 OAuthConsumer 方法。所以我下载了oauth 1.0并添加到我的应用程序中,现在导入这个而不是GAE oauth。
第3期
GAE ssl模块似乎没有CERT_REQUIRED属性。
这是一个常数,所以我改变了
self.cert_reqs = ssl.CERT_REQUIRED
到
self.cert_reqs = 2
调用
时使用ssl.wrap_socket(sock, cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
身份验证错误
但我仍然无法连接到Dropbox:
Status: 401
Reason: Unauthorized
Body: {"error": "Authentication failed"}
Headers: [('date', 'Sun, 19 Feb 2012 15:11:12 GMT'), ('transfer-encoding', 'chunked'), ('connection', 'keep-alive'), ('content-type', 'application/json'), ('server', 'dbws')]
答案 0 :(得分:7)
这是我的Dropbox Python SDK 1.4的修补版本,适用于Python 2.7 GAE:dropbox_python_sdk_gae_patched.7z.base64。不需要额外的第三方库,只需要GAE环境提供的那些。
仅测试文件上传(put_file)。这是设置步骤:
base64.exe -d dropbox_python_sdk_gae_patched.7z.base64 dropbox_python_sdk_gae_patched.7z
。在以下代码中使用:
import dropbox
# ...
def DropboxUpload(path, data):
sess = dropbox.session.DropboxSession(APP_KEY, APP_SECRET, ACCESS_TYPE)
sess.set_token(ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET)
cli = dropbox.client.DropboxClient(sess)
data_file = StringIO.StringIO(data)
return cli.put_file(path, data_file)
# ...
import json
class DropboxUploadHandlerExample(webapp2.RequestHandler):
def get(self):
url = "http://www.google.com/"
result = urlfetch.fetch(url)
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(json.dumps(DropboxUpload('/fetch_result.dat', result.content)))
答案 1 :(得分:3)
我使用自己的修补版本成功从Google Appengine上传到Dropbox Dropbox SDK:https://github.com/cklein/dropbox-client-python
urllib2的使用被huTools.http取代:https://github.com/hudora/huTools/
这是在请求处理程序中调用的代码:
db_client = dropbox.get_dropbox_client(consumer_key='', consumer_secret='', access_token_key='', access_token_secret='')
fileobj = StringIO.StringIO(data)
path = '/some/path/filename'
resp = db_client.put_file(path, fileobj)
fileobj.close()
答案 2 :(得分:3)
截至2016年4月,其他建议均无效。 (Dropbox API版本2,Python SDK版本6.2)。
如果您只需要一些SDK功能,我发现直接使用HTTP API最简单:
def files_upload(f, path, mode='add', autorename=False, mute=False):
args = {
'path': path,
'mode': mode,
'autorename': autorename,
'mute': mute,
}
headers = {
'Authorization': 'Bearer {}'.format(ACCESS_TOKEN),
'Dropbox-API-Arg': json.dumps(args),
'Content-Type': 'application/octet-stream',
}
request = urllib2.Request('https://content.dropboxapi.com/2/files/upload', f, headers=headers)
r = urllib2.urlopen(request)
答案 3 :(得分:1)
我修补了Dropbox Python SDK 2.2版,以便在Google App Engine上运行。请在此处找到相关代码:
https://github.com/duncanhawthorne/gae-dropbox-python
rest.py的相关代码补丁(从github复制)在这里:
import io
import pkg_resources
-import socket
+#import socket
import ssl
import sys
import urllib
+import urllib2
+def mock_urlopen(method,url,body,headers,preload_content):
+ request = urllib2.Request(url, body, headers=headers)
+ r = urllib2.urlopen(request)
+ return r
+
try:
import json
except ImportError:
@@ -23,7 +29,10 @@
SDK_VERSION = "2.2.0"
-TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')
+try:
+ TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')
+except:
+ TRUSTED_CERT_FILE = file('trusted-certs.crt')
class RESTResponse(io.IOBase):
@@ -125,6 +134,7 @@ def flush(self):
pass
def create_connection(address):
+ return
host, port = address
err = None
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
@@ -152,7 +162,7 @@ def json_loadb(data):
class RESTClientObject(object):
- def __init__(self, max_reusable_connections=8, mock_urlopen=None):
+ def __init__(self, max_reusable_connections=8, mock_urlopen=mock_urlopen):
"""
Parameters
max_reusable_connections
@@ -206,7 +216,7 @@ def request(self, method, url, post_params=None, body=None, headers=None, raw_re
raise ValueError("headers should not contain newlines (%s: %s)" %
(key, value))
- try:
+ if True:
# Grab a connection from the pool to make the request.
# We return it to the pool when caller close() the response
urlopen = self.mock_urlopen if self.mock_urlopen else self.pool_manager.urlopen
@@ -217,14 +227,14 @@ def request(self, method, url, post_params=None, body=None, headers=None, raw_re
headers=headers,
preload_content=False
)
- r = RESTResponse(r) # wrap up the urllib3 response before proceeding
- except socket.error as e:
- raise RESTSocketError(url, e)
- except urllib3.exceptions.SSLError as e:
- raise RESTSocketError(url, "SSL certificate error: %s" % e)
+ #r = RESTResponse(r) # wrap up the urllib3 response before proceeding
+ #except socket.error as e:
+ # raise RESTSocketError(url, e)
+ #except urllib3.exceptions.SSLError as e:
+ # raise RESTSocketError(url, "SSL certificate error: %s" % e)
- if r.status not in (200, 206):
- raise ErrorResponse(r, r.read())
+ #if r.status not in (200, 206):
+ # raise ErrorResponse(r, r.read())
return self.process_response(r, raw_response)
@@ -321,10 +331,11 @@ def PUT(cls, *n, **kw):
return cls.IMPL.PUT(*n, **kw)
-class RESTSocketError(socket.error):
+class RESTSocketError():
"""A light wrapper for ``socket.error`` that adds some more information."""
def __init__(self, host, e):
+ return
msg = "Error connecting to \"%s\": %s" % (host, str(e))
socket.error.__init__(self, msg)