Requests works and URLFetch doesn't

I'm trying to make a request to the particle servers in python in a google app engine app.

In my terminal, I can complete the request simply and successfully with requests as:

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

But in my app, the same thing doesn't work with urlfetch, which keeps telling me it can't find the access token:

    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 
    )

I have no idea what the problem is, and no way to debug. Thanks!


In a nutshell, your problem is that in your urlfetch sample you're embedding your access token into the request body, and since you're issuing a GET request -which cannot carry any request body with them- this information gets discarded.

Why does your first snippet work?

Because requests.get() takes that optional params argument that means: "take this dictionary I give you, convert all its key/value pairs into a query string and append it to the main URL"

So, behind the curtains, requests.get() is building a string like this:

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

That's the correct endpoint you should point your GET requests to.

Why doesn't your second snippet work?

This time, urlfetch.fetch() uses a different syntax than requests.get() (but equivalent nonetheless). The important bit to note here is that payload argument doesn't mean the same as our params argument that you used before in requests.get() .

urlfetch.fetch() expects our query string -if any- to be already urlencoded into the URL (that's why urllib.urlencode() comes into play here). On the other hand, payload is where you should put your request body in case you were issuing a POST, PUT or PATCH request, but particle.io's endpoint is not expecting your OAuth access token to be there.

Something like this should work (disclaimer: not tested):

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 
)

Notice how now we don't need your previous Content-type header anymore, since we aren't carrying any content after all. Hence, headers parameter can be removed from this example call.

For further reference, take a look at urlfetch.fetch() reference and this SO thread that will hopefully give you a better insight into HTTP methods, parameters and request bodies than my poor explanation here.

PS: If particle.io servers support it (they should), you should move away from this authentication schema and carry your tokens in a Authorization: Bearer <access_token> header instead. Carrying access tokens in URLs is not a good idea because they are much more visible that way and tend to stay logged in servers, hence posing a security risk. On the other hand, in a TLS session all request headers are always encrypted so your auth tokens are well hidden there.


Ok, so, as it turns out, one cannot include a payload for a GET request using Urlfetch. Instead, one has to include the parameters in the url using the '?' syntax as follows:

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

this worked for me.

链接地址: http://www.djcxy.com/p/41330.html

上一篇: 在java中相当于curl命令

下一篇: 请求有效并且URLFetch不能