【问题标题】:Making HTTP POST request using requests in Python在 Python 中使用请求发出 HTTP POST 请求
【发布时间】:2017-11-28 12:08:56
【问题描述】:

我正在尝试使用 POST 方法向 API 发出 HTTP 请求。我使用的 API 旨在接收三个参数(key1、key2、key3)并返回一个 json 文件。不幸的是,当我使用 data 方法将字典传递给 API 时,我的 POST 请求似乎没有返回任何内容。这似乎很奇怪,因为当我使用 params 方法时它似乎工作。我无法理解这一点,因为这个过程似乎非常不透明(例如,我无法通过 URL 查看有效负载是如何传递到 API 的)。

我的问题:我在这里做错了什么?

使用 data 方法将参数发送到 API 的 POST 请求:

import requests

url = 'http://example.com/API.php'
payload =  {
            'key1': '<<Contains very long json string>>', 
            'key2': 5, 
            'key3': 0
           }

print len(str(payload)) # Prints 6717
r = requests.post(url, data=payload) << Note data is used here
print r.status_code # Prints 200
print r.text # Prints empty string

使用 params 方法将参数发送到 API 的 POST 请求代码:

import requests

url = 'http://example.com/API.php'
payload =  {
            'key1': '<<Contains very long json string>>', 
            'key2': 5, 
            'key3': 0
           }

print len(str(payload)) # Prints 6717
r = requests.post(url, params=payload) << Note here params is used here
print r.status_code # Prints 200
print r.text # Prints expected JSON results

如果您想知道为什么我想使用 data 方法而不是 params... 我正在尝试传递包含更长字符串的其他字典和 params 方法似乎没有这样做,因为我收到 ERROR 414。我希望可以通过使用 data 解决该错误。

我使用的 API 是用 PHP 编写的。

【问题讨论】:

  • API 要求请求正文采用什么编码?它会期待 JSON 或 multipart/form-data 吗?
  • 对不起。目前,我对此并不完全确定,因为 API 是我的同事用 PHP 编写的。但是,我假设 API 需要 JSON。我已经尝试将以下标头与 data 方法一起添加到 HTTP 请求中:headers = {'Content-Type': "application/json; charset=UTF-8"}headers = {'Content-Type': "multipart/form-data; charset=UTF-8"} 他们似乎没有帮助。希望我回答了你的问题。

标签: python api http post


【解决方案1】:

简答
这是因为 params 将参数作为 http POST 请求的一部分发送,而 data 将它们作为请求正文的一部分发送。在您的情况下:只需使用参数调用 api 就可以了。这是绝对正常(和预期)的行为。

演示
只需启动两个命令行。首先,运行 netcat:nc -l 8888。在另一个命令行上,运行 python:

>>> import requests
>>> requests.post('http://localhost:8888',data={'a':1,'b':'2'})

在netcat端,我们看到如下请求:

POST / HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.18.1
Content-Length: 7
Content-Type: application/x-www-form-urlencoded

a=1&b=2

接下来,试试params方式:

>>> requests.post('http://localhost:8888',params={'a':1,'b':'2'})

Netcat 报告:

POST /?a=1&b=2 HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.18.1
Content-Length: 0

注意第一行和最后一行的区别。

正如您从documentation 中看到的那样(斜体强调是我的):

params -- (可选)在查询字符串中为请求发送的字典或字节。
data -- (可选)字典或元​​组列表 [(key, value)](将被形式编码)、字节或类似文件的对象发送在请求的正文中

【讨论】:

  • 感谢您解释 paramsdata 之间的区别。我不明白为什么将我的字典作为正文的一部分发送到 API 不会返回任何内容,而将其作为 HTTP 请求的一部分发送。您认为这可能是 API 方面出现的问题吗?
  • 没有。在这种情况下,这是完全正常的行为。 API 的(http 服务器)只是查看发布的 url 并从那里提取参数。它可能会忽略帖子的内容(数据)。上传带有文件的表单时,带有数据的帖子很常见。表单像“params”一样发送。该文件是使用“数据”发送的。
  • 调用 API 时只需使用参数。我会将其添加到我的答案中,因为这回答了您问题的最后一点
  • 我正在使用多个字典,每个字典代表一个文档。我将每个字典发送到 API 以处理有关文档的一些信息并返回结果。使用 params 对某些词典有效,对其他词典无效。例如,对于文档print len(str(payload)) 打印 18563 - 这显然是一个非常大的字典。如您所料,尝试使用 params 发出 HTTP 请求会引发以下错误:414 Request-URI Too Large - 请求的 URL 的长度超过此服务器的容量限制。
  • 在这种情况下,您应该看到此 API 有哪些其他选项。 RFC 2616 声明对 uri 长度没有先验限制,因此这取决于您要与之交谈的网络服务器。 8KB(8192 字节)是一个常见的限制。超出该大小的任何内容都应与将所有文档数据放在 uri 中不同的方式处理。如果没有更多上下文,我只能建议检查 API 的文档。
猜你喜欢
  • 1970-01-01
  • 2011-04-10
  • 2020-07-14
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 1970-01-01
相关资源
最近更新 更多