遇到问题
在用requests.post方法测试接口调用时,使用data参数得到Response 400结果;使用json参数得到Response 200。测试代码如下。
import requests
import json
url = "https://10.20.32.92:8834/scans"
accesskey = 'dc9ada34d59'
secretkey = 'f3b404a433fea25'
header = {
'X-ApiKeys': 'accessKey={accesskey};secretKey={secretkey}'.format(accesskey=accesskey, secretkey=secretkey),
'X-API-Token':'0FADA7F5-8903-4686-81F7-ECD0096628EA',
'Content-type': 'application/json',
'Accept': 'text/plain'
}
data = {
"uuid":"bbd4f805-3966-d464-b2d1-0079e2bcf",
"settings":{
"name":"testscan",
"enabled": "true",
"text_targets": "ip_list",
"agent_group_id": []
}
}
print(requests.post(url, headers=header, data=data, verify=False))
print(requests.post(url, headers=header, json=data, verify=False))
400与200含义
400 Bad Request --- The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, size too large, invalid request message framing, or deceptive request routing).
200 OK --- Standard response for successful HTTP requests. The actual response will depend on the request method used. In a GET request, the response will contain an entity corresponding to the requested resource. In a POST request, the response will contain an entity describing or containing the result of the action.
data与json区别
从requests的官方文档解释中看出:
data用于发送form-encoded数据,类似HTML表单
json用于发送not form-encoded数据,例如发送字符串。
json参数将Content-Type改为application/json
json参数自动对传入的参数调用json.dumps()
从requests源码中的prepare_body函数中可看出针对json参数,修改了Content-Type以及调用json.dumps()的操作。
这样可能不能很好的理解这两个参数的区别,下面使用https://httpbin.org/post测试,代码如下:
import requests
import json
header = {
'Content-type': 'application/json'
}
data = {
"uuid":"test-uuid",
"settings":{
"name":"test-httpbin",
"enabled": "true",
"text_targets": "ip_list",
}
}
print('\n')
print('-- [ data = data ] -------------------------------------------')
r = requests.post("https://httpbin.org/post", data=data)
print(r.text)
print('\n')
print('-- [ data = json.dumps ] -------------------------------------------')
r = requests.post("https://httpbin.org/post", data=json.dumps(data))
print(r.text)
print('\n')
print('-- [ json = data ] -------------------------------------------')
r = requests.post("https://httpbin.org/post", json=data)
print(r.text)
执行结果如下:
-- [ data = data ] -------------------------------------------
{
"args": {},
"data": "",
"files": {},
"form": {
"settings": [
"name",
"enabled",
"text_targets"
],
"uuid": "test-uuid"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "67",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": null,
"url": "https://httpbin.org/post"
}
-- [ data = json.dumps ] -------------------------------------------
{
"args": {},
"data": "{\"uuid\": \"test-uuid\", \"settings\": {\"name\": \"test-httpbin\", \"enabled\": \"true\", \"text_targets\": \"ip_list\"}}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "105",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": {
"settings": {
"enabled": "true",
"name": "test-httpbin",
"text_targets": "ip_list"
},
"uuid": "test-uuid"
},
"url": "https://httpbin.org/post"
}
-- [ json = data ] -------------------------------------------
{
"args": {},
"data": "{\"uuid\": \"test-uuid\", \"settings\": {\"name\": \"test-httpbin\", \"enabled\": \"true\", \"text_targets\": \"ip_list\"}}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "105",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.22.0"
},
"json": {
"settings": {
"enabled": "true",
"name": "test-httpbin",
"text_targets": "ip_list"
},
"uuid": "test-uuid"
},
"url": "https://httpbin.org/post"
}
从结果可看出data=json.dumps()与json=data是等价的。而它们与data=data的差异在于数据存放的字段不同。
data=data,数据存放在form字段中
json=data,数据存放在data和json字段中
由此可看出,使用requests.post方法中的data或json参数发送数据时,发送的数据被放到不同的键(form或data/json)下。具体从哪个键取数据,这就看接口的实现方式了。因此,若接口从data/json取数据,而调用requests.post方法时使用data参数发送数据,则会导致接口取出的数据为空,从而返回400状态码。
补充1:HTTP状态码分类
HTTP响应状态代码分为五个类别。第一位表示响应的类别,后两位没有分类作用。五个分类如下:
1xx informational response – the request was received, continuing process
2xx successful – the request was successfully received, understood and accepted
3xx redirection – further action needs to be taken in order to complete the request
4xx client error – the request contains bad syntax or cannot be fulfilled
5xx server error – the server failed to fulfill an apparently valid request
补充2:python字典和Json的区别
从字符串的表示规则上看,Python字典和JSON非常相似。但是Python字典本身是一个完整的数据结构,可实现其自己的所有算法。
json的key只能是字符串;Python字典的key可以是任何可hash对象
json的key可以是有序、重复的;Python字典的key不可以重复
json的key存在默认值undefined;Python字典key默认没有默认值
json的value只能是字符串、浮点数、布尔值或者null,或者它们构成的数组或者对象
json访问方式可以是[],也可以是.,遍历方式分in、of;dict的value仅可以下标访问
json的字符串强制双引号;Python字典的字符串可以单引号、双引号
json里只有数组;Python字典可以嵌套tuple
json:true、false、null;python:True、False、None
json中文必须是unicode编码,如"\u6211"
json的类型是字符串;Python字典的类型是字典