Appengie Oauth:电子表格api client.get_spreadsheets()返回错误

时间:2014-02-19 06:57:39

标签: python google-app-engine oauth gdata google-spreadsheet-api

尝试使用oauth&列表来列出Google电子表格Google Appengine中的GData。但是我得到了以下错误。我的代码有什么问题吗?

请告知。

File "/home/RKS/Appengine/test/main.py", line 99, in get
    feed = client.get_spreadsheets()
  File "/home/RKS/Appengine/test/gdata/spreadsheets/client.py", line 78, in get_spreadsheets
    desired_class=desired_class, **kwargs)
  File "/home/RKS/Appengine/test/gdata/client.py", line 640, in get_feed
    **kwargs)
  File "/home/RKS/Appengine/test/gdata/client.py", line 278, in request
    version=get_xml_version(self.api_version))
  File "/home/RKS/Appengine/test/atom/core.py", line 520, in parse
    tree = ElementTree.fromstring(xml_string)
  File "<string>", line 125, in XML
ParseError: no element found: line 1, column 0

代码:

#!/usr/bin/env python

import webapp2
import logging
from google.appengine.api import users

import gdata.auth
import gdata.gauth
import gdata.client
import gdata.service
import gdata.spreadsheets
import gdata.spreadsheets.client
import gdata.spreadsheets.data

SETTINGS = {
    'APP_NAME': 'hidden',  # intentionally hidden
    'CONSUMER_KEY': 'hidden',
    'CONSUMER_SECRET': 'hidden',
    'SCOPES': ['https://spreadsheets.google.com/feeds'],
    'CALLBACK_URL': '',
    'SIG_METHOD': gdata.auth.OAuthSignatureMethod.HMAC_SHA1
}

class FetchToken(webapp2.RequestHandler):
    def get(self):
        current_uid = users.get_current_user().user_id()
        if isinstance(gdata.gauth.AeLoad(current_uid), gdata.gauth.OAuthHmacToken):
            # the user has gone through the process before
            self.redirect('/')
        else:
              # the user has not gone through this process, or the authorization has expired or been revoked.
            SETTINGS['CALLBACK_URL'] = 'http://%s/HandleOAuthCallback' % self.request.host
            client = gdata.client.GDClient()
            request_token = client.GetOAuthToken(
                SETTINGS['SCOPES'],
                SETTINGS['CALLBACK_URL'],
                SETTINGS['CONSUMER_KEY'],
                consumer_secret=SETTINGS['CONSUMER_SECRET'])

            gdata.gauth.AeSave(request_token, current_uid)
            self.redirect(str(request_token.generate_authorization_url()))


class HandleOAuthCallback(webapp2.RequestHandler):
    def get(self):
        current_uid = users.get_current_user().user_id()
        client = gdata.client.GDClient()
        saved_request_token = gdata.gauth.AeLoad(current_uid)
        request_token = gdata.gauth.AuthorizeRequestToken(saved_request_token, self.request.uri)
        access_token = client.GetAccessToken(request_token)
        gdata.gauth.AeSave(access_token, current_uid)
        self.redirect('/')


class GetDocsList(webapp2.RequestHandler):
    def get(self):
        if not users.get_current_user():
            self.redirect(users.create_login_url('/'))
        else:
            current_uid = users.get_current_user().user_id()
            if isinstance(gdata.gauth.AeLoad(current_uid), gdata.gauth.OAuthHmacToken):
                # the user has gone through the process before

                access_token = gdata.gauth.AeLoad(current_uid)
                client = gdata.service.GDataService()

                oauth_input_params = gdata.auth.OAuthInputParams(
                    gdata.auth.OAuthSignatureMethod.HMAC_SHA1,
                    SETTINGS['CONSUMER_KEY'],
                    SETTINGS['CONSUMER_SECRET'])  # consumer_secret=

                oauth_token = gdata.auth.OAuthToken(
                    key=access_token.token,
                    secret=access_token.token_secret,
                    scopes=SETTINGS['SCOPES'],
                    oauth_input_params=oauth_input_params)

                client.SetOAuthToken(oauth_token)

                client = gdata.spreadsheets.client.SpreadsheetsClient()

                feed = client.get_spreadsheets()

            else:
                self.redirect('/FetchToken')


app = webapp2.WSGIApplication([('/HandleOAuthCallback', HandleOAuthCallback), ('/', GetDocsList), ('/FetchToken', FetchToken)], debug=False)

1 个答案:

答案 0 :(得分:0)

我建议切换到OAuth2,我的大部分答案将解释如何通过这样做来解决您的问题。但是,在尝试切换到OAuth2之前,我建议您尝试这一行更改,这可能是您问题的快速解决方案。我要尝试的第一件事是向客户端添加标题,如下所示。

client.additional_headers = {
  'Authorization': 'Bearer %s' % access_token,
}

我有一个使用GData电子表格API和OAuth2的应用程序,并添加该标头是必要的。如果我拿出那个标题,我会得到一个像你描述的错误。

现在,回答: 在App Engine中使用OAuth2执行您尝试执行的操作甚至比您已经完成的操作更简单。以下是它的完成方式。

首先创建一个OAuth2装饰器。 (我将在答案结尾处描述在何处创建客户端ID和客户端密码。)

from oauth2client.appengine import OAuth2Decorator
GlobalOAuth2Decorator = OAuth2Decorator(
  client_id=OAUTH2_CLIENT_ID,
  client_secret=OAUTH2_CLIENT_SECRET,
  scope='https://spreadsheets.google.com/feeds',
)

然后在创建请求处理程序时使用此装饰器。

class SpreadsheetHandler(webapp2.RequestHandler):
  @GlobalOAuth2Decorator.oauth_required
  def get(self):
    client = gdata.spreadsheet.service.SpreadsheetsService()
    client.additional_headers = {
      'Authorization': 'Bearer %s' % GlobalOAuth2Decorator.credentials.access_token,
    }

请注意,我使用SpreadsheetsService而不是SpreadsheetsClient。这对我来说很有用,虽然我没有尝试过SpreadsheetsClient(客户端实际上可能更容易使用)。

创建此client对象后,您可以根据需要使用它来读取和编写电子表格。例如,sheets = client.GetSpreadsheetsFeeds()会为您提供可以访问的电子表格列表。

最后,确保在创建应用程序时在您的处理程序列表中包含OAuth处理程序:

app = webapp2.WSGIApplication([..., (GlobalOAuth2Decorator.callback_path, GlobalOAuth2Decorator.callback_handler())]

要使OAuth2正常工作,您必须在https://console.developers.google.com转到开发人员控制台,然后1)从“凭据”菜单中选择您的应用,2)创建新的客户端ID(这将生成客户端ID和您的秘密),3)从同意屏幕菜单中为您的应用程序提供一个电子邮件地址和名称。