请求有效而 URLFetch 无效

Requests works and URLFetch doesn't

我正尝试在 google 应用引擎应用中向 python 中的粒子服务器发出请求。

在我的终端中,我可以简单而成功地完成请求,请求如下:

res = requests.get('https://api.particle.io/v1/devices', params={"access_token": {ACCESS_TOKEN}})

但在我的应用程序中,同样的事情不适用于 urlfetch,它一直告诉我找不到访问令牌:

    url = 'https://api.particle.io/v1/devices'
    payload = {"access_token": {ACCESS_TOKEN}}
    form_data = urllib.urlencode(payload)
    res = urlfetch.fetch(
        url=url,
        payload=form_data,
        method=urlfetch.GET,
        headers={
            'Content-Type':
            'application/x-www-form-urlencoded'
        },
        follow_redirects=False 
    )

我不知道是什么问题,也没有办法调试。谢谢!

简而言之,您的问题是,在您的 urlfetch 示例中,您将访问令牌嵌入到请求 body 中,并且由于您发出的是 GET 请求 - 无法携带与他们的任何请求 body - 此信息将被丢弃。

为什么您的第一个代码段有效?

因为 requests.get() 采用可选的 params 参数,这意味着:"take this dictionary I give you, convert all its key/value pairs into a query string and append it to the main URL"

所以,在幕后,requests.get() 正在构建这样一个字符串:

https://api.particle.io/v1/devices?access_token=ACCESS_TOKEN

这是您应该将 GET 请求指向的正确端点。

为什么你的第二个代码段不起作用?

这一次,urlfetch.fetch() 使用与 requests.get() 不同的语法(但仍然等效)。这里需要注意的重要一点是 payload 参数 requests.get() 之前使用的 params 参数的含义不同

urlfetch.fetch() 期望我们的查询字符串 - 如果有的话 - 已经被 urlencoded 到 URL (这就是 urllib.urlencode() 在这里发挥作用的原因)。另一方面,payload 是您应该放置请求 body 的地方,以防您发出 POST、PUT 或 PATCH 请求,但 particle.io 的端点不是期待您的 OAuth 访问令牌在那里。

这样的东西应该可以工作(免责声明:未测试):

auth = {"access_token": {ACCESS_TOKEN}}
url_params = urllib.urlencode(auth)
url = 'https://api.particle.io/v1/devices?%s' % url_params

res = urlfetch.fetch(
    url=url,
    method=urlfetch.GET,
    follow_redirects=False 
)

请注意,现在我们不再需要您之前的 Content-type header,因为我们毕竟没有携带任何内容。因此,可以从此示例调用中删除 headers 参数。

如需进一步参考,请查看 urlfetch.fetch() reference and this SO thread,与我在此处的拙劣解释相比,它有望让您更好地了解 HTTP 方法、参数和请求主体。

PS: 如果 particle.io 服务器支持(他们应该支持),您应该远离此身份验证模式并将您的令牌放在 Authorization: Bearer <access_token> header 代替。在 URLs 中携带访问令牌不是一个好主意,因为这样它们更容易看到并且倾向于保持登录在服务器中,因此会带来安全风险。另一方面,在 TLS session 中,所有请求 header 总是被加密,因此您的身份验证令牌被很好地隐藏在那里。

好的,事实证明,不能使用 Urlfetch 为 GET 请求包含有效负载。相反,必须使用“?”将参数包含在 url 中。语法如下:

url = 'https://api.particle.io/v1/devices'
url = url + '?access_token=' + {ACCESS_TOKEN}
res = urlfetch.fetch(
    url=url,
    method=urlfetch.GET,
    follow_redirects=False 
)

这对我有用。