这两个请求有什么区别?

What is the difference between those two requests?

对于任务自动化,我需要编写一些 python 代码,它向 Web 服务发出 post 请求,然后检索信息等。

首先我尝试使用请求。

import requests

def make_invoice_body(terminal, service, code, number):
    return {
        "terminalId": terminal,
        "serviceId" : service,
        "invoiceNumber": number,
        "invoiceCode": code,
        "paymentType": 1,
        "requestNumber": random.randint(1000000, 9999999)
    }

headers = {'Content-Type': 'application/json'}
body = make_invoice_body(51, "1001000", "FOO", "123456")

requests.post(url, headers=headers, data=body)   

以上代码段收到错误作为响应。

然后我尝试使用 urllib2

import urllib2
import json

req = urllib2.Request(url)
req.add_header('Content-Type', 'application/json')
resp = urllib2.urlopen(req, body) #body from above
print resp.read()

它奏效了。

现在我很好奇上述片段的不同之处。他们不应该做同样的任务并得到相同的答案吗?

从 Requests 版本 2.4.2 开始,您可以在请求中使用 json 参数作为

requests.post(url, headers=headers, json=body) 

如果你使用json参数,你也可以去掉'application/json' header因为json参数让它变得多余

如果你想使用数据,你需要先使用

将你的字典转换为 json
data = json.dumps(body)

HTTP 世界中没有 "native dict" 格式。

真正不同的是requests太聪明了

requests 中使用 data= 时,您正在尝试 post multipart/form-data。在这种情况下,dict 将以 form-data 格式解压成 key-value 对。

当在 requests 中使用 json= 时,requests 将自动 json.dumps 您的 dict 到原始字节字符串中并设置 Content-Type你.

但在urllib,它所做的只是你的付出。您需要手动 json.dumps 您的 dict。所以我相信你举的例子是错误的。它应该像下面这样:

import urllib2
import json

req = urllib2.Request(url)
req.add_header('Content-Type', 'application/json')
resp = urllib2.urlopen(req, json.dumps(body)) #body from above
print resp.read()

感谢@t.m.adam的提醒。