使用 Uber Rides Python SDK 检索数据失败并出现 500 错误

Retrieve data with Uber Rides Python SDK fails with 500 error

遵循本教程 https://developer.uber.com/docs/riders/ride-requests/tutorials/api/python 后,我在尝试获取用户个人资料或 activity.

等数据时遇到错误

这是我的示例(Flask)代码:

import os
from datetime import datetime
from flask import Flask, request, flash, url_for, redirect, \
     render_template, abort, send_from_directory, redirect

from uber_rides.auth import AuthorizationCodeGrant
from uber_rides.session import Session
from uber_rides.client import UberRidesClient

app = Flask(__name__)
app.config.from_pyfile('flaskapp.cfg')

# Configure Uber Oauth2.0
auth_flow = AuthorizationCodeGrant(
    '<client_id>',
    ['profile', 'history'],
    '<client_secret>',
    'http://localhost:8080/callback'
    )

@app.route('/')
def index():
    auth_url = auth_flow.get_authorization_url()
    return redirect(auth_url, code=302)

@app.route('/callback')
def callback():
    session = auth_flow.get_session(request.url)
    client = UberRidesClient(session)
    credentials = session.oauth2credential

    # Fetch users profile
    response = client.get_user_profile()
    profile = response.json

    first_name = profile.get('first_name')
    last_name = profile.get('last_name')
    email = profile.get('email')

    # Fetch user activity
    response = client.get_user_activity()
    history = response.json

    return first_name, 200

if __name__ == '__main__':
    app.run(debug=True)

错误痕迹:

Starting WSGIServer type flask on 127.0.0.1:8080 ...
 * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
127.0.0.1 - - [11/Jan/2017 21:11:53] "GET / HTTP/1.1" 302 -
127.0.0.1 - - [11/Jan/2017 21:12:09] "GET /callback?state=VFI3w30Haz5MUb1jvaLxDsCdMduVedLv&code=NSol8RDwh5zbLYL4ef0U96ePjsZZ6l HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/werkzeug/serving.py", line 205, in run_wsgi
    execute(self.server.app)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/werkzeug/serving.py", line 193, in execute
    application_iter = app(environ, start_response)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1994, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1994, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/crazywizard/Documents/uber/flaskapp.py", line 41, in callback
    response = client.get_user_activity()
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/uber_rides/client.py", line 260, in get_user_activity
    return self._api_call('GET', 'v1.2/history', args=args)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/uber_rides/client.py", line 104, in _api_call
    return request.execute()
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/uber_rides/request.py", line 152, in execute
    return self._send(prepared_request)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/uber_rides/request.py", line 136, in _send
    response = session.send(prepared_request)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/requests/sessions.py", line 615, in send
    r = dispatch_hook('response', hooks, r, **kwargs)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/requests/hooks.py", line 31, in dispatch_hook
    _hook_data = hook(hook_data, **kwargs)
  File "/Users/crazywizard/Documents/uber/venv/lib/python2.7/site-packages/uber_rides/utils/handlers.py", line 63, in error_handler
    raise ServerError(response, error_message)
ServerError: 500: We have experienced a problem.

这会不会是 Uber 服务的问题?

更新: 请求调试跟踪。

Starting WSGIServer type flask on 127.0.0.1:8080 ...
INFO:werkzeug: * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
INFO:werkzeug:127.0.0.1 - - [15/Jan/2017 18:58:09] "GET / HTTP/1.1" 302 -
DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): login.uber.com
DEBUG:requests.packages.urllib3.connectionpool:https://login.uber.com:443 "POST /oauth/token HTTP/1.1" 200 None
INFO:werkzeug:127.0.0.1 - - [15/Jan/2017 18:58:19] "GET /callback?state=z9ga01Y6kgNFRbgDbeEA3IjCYLMTnI7M&code=wwTzfIbFivsCoGE4RIu0rDb2fO22NI HTTP/1.1" 200 -
DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): sandbox-api.uber.com
DEBUG:requests.packages.urllib3.connectionpool:https://sandbox-api.uber.com:443 "GET /v1.2/me HTTP/1.1" 500 75
INFO:werkzeug:127.0.0.1 - - [15/Jan/2017 18:58:35] "GET /profile HTTP/1.1" 500 -
ERROR:werkzeug:Error on request:

更新 2: 请求模块日志记录

Starting WSGIServer type flask on 127.0.0.1:8080 ...
INFO:werkzeug: * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
^C(venv) Davids-MacBook-Pro:uber crazywizard$ clear
(venv) Davids-MacBook-Pro:uber crazywizard$ python app.py
Starting WSGIServer type flask on 127.0.0.1:8080 ...
INFO:werkzeug: * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
INFO:werkzeug:127.0.0.1 - - [17/Jan/2017 22:35:04] "GET / HTTP/1.1" 302 -
DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): login.uber.com
send: 'POST /oauth/token HTTP/1.1\r\nHost: login.uber.com\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: python-requests/2.12.4\r\nContent-Length: 217\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\ncode=Mg1VBWKR0V0ioeLYTAv61pAbjy3WD4&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fcallback&client_id=xxx&client_secret=xxx&grant_type=authorization_code'
reply: 'HTTP/1.1 200 OK\r\n'
header: Server: nginx
header: Date: Tue, 17 Jan 2017 19:35:08 GMT
header: Content-Type: application/json
header: Transfer-Encoding: chunked
header: Connection: keep-alive
header: Pragma: no-cache
header: Cache-Control: no-store
header: Set-Cookie: session=ab5c70960ceb1415_587e71ec.pJiJyH80bf4wULzs_NpDCMc-Ymw; Domain=login.uber.com; Secure; HttpOnly; Path=/
header: X-Uber-App: login
header: Strict-Transport-Security: max-age=604800
header: X-Content-Type-Options: nosniff
header: X-XSS-Protection: 1; mode=block
header: Strict-Transport-Security: max-age=2592000
header: X-Frame-Options: SAMEORIGIN
header: Cache-Control: max-age=0
header: Content-Encoding: gzip
DEBUG:requests.packages.urllib3.connectionpool:https://login.uber.com:443 "POST /oauth/token HTTP/1.1" 200 None
DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): sandbox-api.uber.com
send: 'GET /v1/products?latitude=37.77&longitude=-122.41 HTTP/1.1\r\nHost: sandbox-api.uber.com\r\nAccept-Encoding: identity\r\nX-Uber-User-Agent: Python Rides SDK v0.2.7\r\nAuthorization: Bearer xxx\r\n\r\n'
reply: 'HTTP/1.1 500 Internal Server Error\r\n'
header: Server: nginx
header: Date: Tue, 17 Jan 2017 19:35:09 GMT
header: Content-Type: application/json
header: Content-Length: 75
header: Connection: keep-alive
header: X-Uber-App: uberex-sandbox
header: X-Uber-App: migrator-uberex-sandbox-optimus
header: Strict-Transport-Security: max-age=604800
header: X-Content-Type-Options: nosniff
header: X-XSS-Protection: 1; mode=block
DEBUG:requests.packages.urllib3.connectionpool:https://sandbox-api.uber.com:443 "GET /v1/products?latitude=37.77&longitude=-122.41 HTTP/1.1" 500 75
INFO:werkzeug:127.0.0.1 - - [17/Jan/2017 22:35:10] "GET /callback?state=dH1nnut35q9xcOdC3W9a1lFKNqGXn9h5&code=Mg1VBWKR0V0ioeLYTAv61pAbjy3WD4 HTTP/1.1" 500 -
ERROR:werkzeug:Error on request:

更新 3: 我已经深入研究 rides_python_sdk 并添加了额外的 headers,如文档 https://developer.uber.com/docs/riders/ride-requests/tutorials/api/curl#get-a-list-of-products-available

所示

我还将 Accept-Encoding 参数更正为 sdk ['gzip, deflate']

中的内容

仍然出现 500 错误

DEBUG:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): api.uber.com
send: 'GET /v1.2/products?latitude=37.77&longitude=-122.41 HTTP/1.1\r\nHost: api.uber.com\r\nAccept-Language: en_EN\r\nX-Uber-User-Agent: Python Rides SDK v0.3.1\r\nContent-Type: application/json\r\nAccept-Encoding: gzip, deflate\r\nAuthorization: Bearer ppdHHakR8EQL09kpAIrPYkDCAWFHQT\r\n\r\n'
reply: 'HTTP/1.1 500 Internal Server Error\r\n'
header: Server: nginx
header: Date: Wed, 18 Jan 2017 09:46:04 GMT
header: Content-Type: application/json
header: Content-Length: 75
header: Connection: keep-alive
header: X-Uber-App: uberex-nonsandbox
header: X-Uber-App: migrator-uberex-optimus
header: Strict-Transport-Security: max-age=604800
header: X-Content-Type-Options: nosniff
header: X-XSS-Protection: 1; mode=block

感谢您在我调查此问题时的耐心等待。这是我们的 v1 oauth 端点中的一个潜在错误,它影响了新创建的应用程序。我已经发布了一个新版本的 sdk 来解决这个问题。请使用 v0.4.0,你应该不会有任何问题。感谢您的详细反馈!

我不得不使用另一个 oauth 库(flask_oauthlib)。

import os, requests, logging
import httplib as http_client
from datetime import datetime
from flask import Flask, request, flash, url_for, redirect

from flask_oauthlib.client import OAuth
from flask import session, redirect

app = Flask(__name__)
app.config.from_pyfile('flaskapp.cfg')

http_client.HTTPConnection.debuglevel = 1
logging.basicConfig(level=logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

oauth = OAuth()
uber_app = oauth.remote_app(
        'uber',
        request_token_url=None,
        access_token_url='https://login.uber.com/oauth/v2/token',
        authorize_url='https://login.uber.com/oauth/v2/authorize',
        consumer_key='<client_id>',
        consumer_secret='<client_secret>'
    )

@app.route('/')
def index():
    #Make call to Uber service to retrieve products
    headers = {'Authorization' : 'Bearer '+session['uber_token'][0]}
    url = "https://api.uber.com/v1.2/"
    response_profile = requests.get(url+'me', headers=headers)
    response_history = requests.get(url+'history', headers=headers)

    return "<h3>Profile</h3><p>"+response_profile.content+"<h3>History</h3>"+response_history.content, 200

@uber_app.tokengetter
def get_uber_token(token=None):
    return session.get('uber_token')

@app.route('/login')
def login():
    return uber_app.authorize(callback=url_for('oauth_authorized', _external=True,
        next=request.args.get('next') or request.referrer or None))

@app.route('/oauth-authorized')
def oauth_authorized():
    next_url = request.args.get('next') or url_for('index')
    resp = uber_app.authorized_response()
    if resp is None:
        flash(u'You denied the request to sign in.')
        return redirect(next_url)

    session['uber_token'] = (
        resp['access_token'],
        resp['refresh_token']
    )

    flash('You were signed in')
    return redirect(next_url)

if __name__ == '__main__':
    app.run(debug=True)
  1. 首先创建一个oauth实例并将参数分配给remote_app方法。

注: oauth2.0 没有request_token_url,所以设置为None.

  1. get_uber_token 方法创建一个全局 session 来存储您的令牌,可以从代码中的其他任何地方访问它。

  2. /login 将用户重定向到 Uber 登录页面。作为 url 的一部分,优步将使用重定向 uri 回调您的服务。

注意:确保在url_for方法中添加_external=True参数,以便生成需要的绝对url用于回调的优步服务。

  1. 'oauth_authorized' 方法和端点在授权阶段后处理来自 Uber 服务的重定向。请记住获取并存储您稍后需要的两个重要令牌; access_tokenrefresh_token

  2. 在授权成功后最终重定向到的index方法中,我进行了几次调用以获取个人资料和骑手历史记录以进行演示。留意发送的headers

注意: 请注意,Bearer 令牌将在大约 10 分钟后过期,之后您将需要刷新令牌来请求另一个 Bearer 令牌。此处的日志记录只是将所有内容设置为 DEBUG 级别,因此您可以查看在线发送的内容。