11

I am using python requests module, I send my params like this before:

requests.post(url=url, params=params)

but today, I find that I send my data like this, it fails, I change to this:

requests.post(url=url, data=params)

then it is ok, what is the difference between data and params?

I observed that the request got a header X-Requested-With:XMLHttpRequest, is it because of this?

pnuts
  • 58,317
  • 11
  • 87
  • 139
roger
  • 9,063
  • 20
  • 72
  • 119
  • Are you sure you weren't getting rather than posting? – Peter Wood Nov 03 '15 at 10:44
  • what was the error you got when sending it in params? – Ross Drew Nov 03 '15 at 11:01
  • roger, shame on you. As u can easily check in the history log of this thread, I was the first one answering your question correctly, while @ZN13 gave an incorrect answer. Then, AFTER my answer, he edited his answer and corrected it, and u finally marked his answer as the good one. That behaviour from him is sad, but u are encouraging it by rewarding him like that. I am glad that the overwhelming majority of this community is not like u guys. – thelawnmowerman Mar 22 '22 at 11:58

3 Answers3

18

According to the requests documentation:

  • A requests.post(url, data=data) will make an HTTP POST request, and
  • A requests.get(url, params=params) will make an HTTP GET request

To understand the difference between the two, see this answer.

Here's how params can be used in a GET:

payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.text)

Which outputs

{
  "args": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  [...]
  "url": "http://httpbin.org/get?key1=value1&key2=value2"
}

Notice that the payload ended up in the query string of the URL. Since they ended up there, they are viewable by anyone who has access to the URL, which is why you shouldn't use query strings for sensitive data like passwords.

Here's how data can be used in a POST:

payload = 'foobar'
r = requests.post('http://httpbin.org/post', data=payload)
print(r.text)

Which outputs

{
  "args": {}, 
  "data": "foobar", 
  [...]
  "url": "http://httpbin.org/post"
}

Notice how the POST data does not show up in the query strings, as they are transmitted through the body of the request instead.


Critique of this answer has pointed out that there are more options. I never denied such a thing in my original answer, but let's take a closer look.

The documentation examples always show:

  • The params keyword used for GET, and
  • The data keyword used for POST

But that doesn't mean they are mutually exclusive.

In theory you could mix the two together in a POST:

data = 'foobar'
params = {'key1': 'value1', 'key2': 'value2'}
r = requests.post('http://httpbin.org/post', params=params, data=data)
print(r.text)

Which outputs

{
  "args": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  "data": "foobar", 
  [...]
  "url": "http://httpbin.org/post?key1=value1&key2=value2"
}

But you cannot mix data into a GET:

data = 'foobar'
params = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=params, data=data)
print(r.text)

Outputs:

{
  "args": {
    "key1": "value1", 
    "key2": "value2"
  }, 
  [...]
  "url": "http://httpbin.org/get?key1=value1&key2=value2"
}

Notice how the data field is gone.

ZN13
  • 1,048
  • 1
  • 11
  • 21
  • post will not send data in URL. get method does. – Sekar Ramu Nov 15 '18 at 13:25
  • @SekarRamu It seems that the code example I wrote was right, but I mistyped the text above so instead of `requests.get` I wrote `requests.post`. This should now be fixed. – ZN13 Dec 04 '18 at 16:28
6

First of all, there are two different methods:

  • requests.post() makes a POST request (placing all the parameters in the body)
  • requests.get() makes a GET request (placing all the parameters in the URL)

Then, according to the docs, you can choose between two parameters to send all the key/value data:

  • params=, without string modifications.
  • data=, applying a form-encoding string modification to the parameters.

So, you have 4 choices to send your request:

  • requests.post(url, params=)
  • requests.post(url, data=)
  • requests.get(url, params=)
  • requests.get(url, data=)

I don't think the currently accepted answer is correct. He is actually talking about requests.post() but using requests.get() in his own example.

thelawnmowerman
  • 11,956
  • 2
  • 23
  • 36
  • Wrong. You cannot use the data keyword in a GET request. It just silently removes it. – ZN13 Jun 10 '20 at 07:29
1

Params are sent in (appended to) the URI (http://www.answer.com/here?param1=1&param2=2) while data is sent in the request body. Usually sensitive data or that sent in large volumes is posted in the body because it's easier to secure and doesn't lead to huge URIs.

Community
  • 1
  • 1
Ross Drew
  • 8,163
  • 2
  • 41
  • 53
  • Why is it easier to secure? – Peter Wood Nov 03 '15 at 11:08
  • 1
    Because URIs are sent in plaintext and normally stored in server logs so if you are sending something like a security token/username/password then anyone can see (and use) it. – Ross Drew Nov 03 '15 at 11:16
  • The data could still be sniffed. You can use `https://` to secure. edit: **No you can't** – Peter Wood Nov 03 '15 at 11:19
  • No, you can't. That secures only network level attacks http://blog.httpwatch.com/2009/02/20/how-secure-are-query-strings-over-https/ – Ross Drew Nov 03 '15 at 11:20
  • 1
    Thanks for the link. That's horrific. And also really helpful and informative. – Peter Wood Nov 03 '15 at 11:22
  • @ZN13 r = requests.post('http://httpbin.org/post', data=payload) should place the payload under 'forms' not 'data', unless you add a header which includes the content-type – blessedk Dec 27 '21 at 21:15