Google app engine 从GAE将文件写入Dropbox帐户

Google app engine 从GAE将文件写入Dropbox帐户,google-app-engine,dropbox-api,Google App Engine,Dropbox Api,我正在尝试从GAE应用程序在Dropbox.com文件夹中创建文件。 我已经完成了注册Dropbox应用程序的所有步骤,并在我的开发机器上从Dropbox本地安装了Python SDK。(参见dropbox.com API)。 当我在本地机器上使用dropbox SDK中的cli_client.py测试脚本来访问dropbox-can'put'文件等时,这一切都非常有效 我现在想开始在GAE环境中工作,所以事情变得有点棘手。 一些帮助会有用的 对于那些熟悉Dropbox API代码的人,到目前为

我正在尝试从GAE应用程序在Dropbox.com文件夹中创建文件。 我已经完成了注册Dropbox应用程序的所有步骤,并在我的开发机器上从Dropbox本地安装了Python SDK。(参见dropbox.com API)。 当我在本地机器上使用dropbox SDK中的cli_client.py测试脚本来访问dropbox-can'put'文件等时,这一切都非常有效

我现在想开始在GAE环境中工作,所以事情变得有点棘手。 一些帮助会有用的

对于那些熟悉Dropbox API代码的人,到目前为止,我遇到了以下问题:

第1期

rest.py Dropbox API模块使用pkg_资源将证书安装在本地计算机安装的站点包中。 我换了

TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')

并将证书文件放在我的GAE应用程序目录中。也许这并不完全正确;请参阅下面的我的身份验证错误代码

第二期

py Dropbox API模块使用oauth模块,因此我将include更改为appengine oauth

但是引发了一个异常,即GAE的oauth没有Dropbox session.py模块使用的OAuthConsumer方法。所以我下载了oauth 1.0,并在我的应用程序中添加了一个now import,而不是GAE oauth

第三期

GAE ssl模块似乎没有CERT_REQUIRED属性

这是一个常数,所以我改变了

self.cert_reqs = ssl.CERT_REQUIRED

这是在呼叫时使用的

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')]

我用自己的补丁版本成功地从谷歌Appengine上传到Dropbox Dropbox SDK的功能:

urllib2的用法已被huTools.http取代:

这是在请求处理程序中调用的代码:

    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()

这是我的Dropbox Python SDK 1.4的补丁版本,它在Python 2.7 GAE中运行良好:。不需要额外的第三方库,只需要GAE环境提供的库

仅测试文件上载(put_文件)。以下是安装步骤:

  • 将存档解压缩到GAE应用程序的根文件夹(如果主应用程序位于根文件夹中)。您可以使用以下命令解码BASE64:
    BASE64.exe-d dropbox\u python\u sdk\u gae\u patched.7z.BASE64 dropbox\u python\u sdk\u gae\u patched.7z
  • 设置应用程序密钥、应用程序密钥、访问类型、访问令牌密钥、访问令牌密钥。前三个在dropbox应用程序创建时配置。最后两个是在授予应用程序对特定dropbox帐户的访问权限时获得的,您可以通过cli_client.py(来自DB Python SDK)从token_store.txt文件获得它们
  • 在代码中使用如下内容:

    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)))
    

  • 我已经修补了Dropbox Python SDK 2.2版,以便在Google应用程序引擎上工作。请在此处查找相关代码:

    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)
    

    截至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)
    

    我希望有人能回答这个问题。同时,虽然我不确定pkg_resources.resource_filename()是什么,但我认为它会返回一个文件名,而不是一个打开的文件,而file()会打开命名文件并返回一个流(打开的文件)对象。您可能希望尝试使用
    TRUSTED\u CERT\u FILE='TRUSTED certs.crt'
    代替。Guido,您是正确的,pkg\u resources.resource\u filename()返回的类型是'str'。该值是证书文件的完整路径。所以我按照你的建议做了改变。唉,还是同样的错误。我目前正在处理同样的问题。我已经修补了Dropbox SDK代码,我可能很快就能回答。谢谢Chris-我在下面看到了你的答案。你能把这个更新到最新的Dropbox SDK吗?它有Dropbox OAuth2FlowNoreDirect吗?
     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)
    
    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)