我在使用自定义标头进行发布请求时遇到一些问题。 我正在使用Requests库,并作为端点jsonplaceholder,在这里您可以通过POST请求获得伪造的JSON。
我用
调用脚本py request.py
// request.py
import requests
import json
from pprint import pprint
def postReqCustom( url, headers, data):
print('Making request to: ', url)
r = requests.post(url, headers=headers, data=data)
print('status code: ' + str(r.status_code))
response = r.json()
pprint(response)
def postReq( url, data):
print('Making request to: ', url)
r = requests.post(url, data=data)
print('status code: ' + str(r.status_code))
response = r.json()
pprint(response)
headers = {'content-type': 'application/json'}
data = {
"title": "foo",
"body": "bar",
"userId": 1
}
post_url = "https://jsonplaceholder.typicode.com/posts"
#postReq(post_url, data) #ok
postReqCustom(post_url, headers, data) #error
对于postReq
,我没有收到任何错误(状态码201),但是当我尝试使用自定义标头进行postReqCustom
时,却遇到了以下错误:
Making request to: https://jsonplaceholder.typicode.com/posts
status code: 500
Traceback (most recent call last):
File "request.py", line 55, in <module>
postReqCustom(post_url, headers, payload)
File "request.py", line 24, in postReqCustom
response = r.json()
File "C:\Users\Samy\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\models.py", line 892, in json
return complexjson.loads(self.text, **kwargs)
File "C:\Users\Samy\AppData\Local\Programs\Python\Python36-32\lib\json\__init__.py", line 354, in loads
return _default_decoder.decode(s)
File "C:\Users\Samy\AppData\Local\Programs\Python\Python36-32\lib\json\decoder.py", line 339, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\Samy\AppData\Local\Programs\Python\Python36-32\lib\json\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
答案 0 :(得分:2)
问题是您正在使用data=data
。与the docs explain一样,如果您使用此参数并传递除字符串以外的任何内容, 1 它将对数据进行形式编码,如下所示:
title=foo&body=bar&userId=1
默认情况下,它还将Content-Type
标头设置为application/x-www-form-urlencoded
,因此一切正常。
但是,如果您使用application/json
覆盖该标头,那么现在将服务器主体title=foo&body=bar&userId=1
传递给服务器,并告诉服务器将其解码为JSON。当然哪个会失败,所以服务器给您一个错误也就不足为奇了。 2
如果您希望您的值采用JSON编码而不是形式编码,请使用json
参数,而不要使用data
参数:
r = requests.post(url, headers=headers, json=data)
此JSON编码数据,如下所示:
{"title": "foo", "body": "bar", "userId": 1}
它还将默认将Content-Type
设置为application/json
,因此一切正常。当然,如果您用相同的值覆盖相同的标头,它将仍然具有相同的作用。
如果要手动进行编码并发送任何编码的字符串,可以使用data
,但随后必须发送一个字符串。例如(直接从同一“文档”部分中删除):
r = requests.post(url, headers=headers, data=json.dumps(data))
1。此处将Unicode str
以及类似编码的bytes
和bytes
的类型都视为字符串,但这在快速入门教程中没有说明。
2。当然,真正的服务器应该并且可能会返回一个400 Bad Request
,而不是尝试执行没有意义的操作,遇到意外错误并仅仅使用500 Internal Server Error
。 sub>
答案 1 :(得分:-1)
细读代码后;我可以说您正确实现了自定义标头。看完用于模拟REST端点的服务后,似乎它不接受application / json MIME类型。这是您的端点接受的内容:
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
在将标头字典更改为“ Content-Type”:“ text / xml”后,一切运行良好(得到201):
import requests
import json
from pprint import pprint
def postReqCustom( url, headers, data):
print('Making request to: ', url)
r = requests.post(url, headers=headers, data=data)
print('status code: ' + str(r.status_code))
response = r.raise_for_status()
pprint(response)
def postReq( url, data):
print('Making request to: ', url)
r = requests.post(url, data=data)
print('status code: ' + str(r.status_code))
response = r.json()
pprint(response)
headers = {'content-type': 'application/xml'}
data = {
"title": "foo",
"body": "bar",
"userId": 1
}
post_url = "https://jsonplaceholder.typicode.com/posts"
postReqCustom(post_url, headers, data)