作者曾经看过很多python-requests接口自动化框架和平台,发现很多底层引擎写的并不严谨,所以特此写了一份实测文章,欢迎保存收藏。
每种请求均以下列输出代码来展示具体详情,也可以作为从请求中提取参数的代码:
一. Params
简介:就是放在url中的参数,在url结尾用?来接,并且多个参数之间用&分割。这个不区分get还是post,也不会和请求体参数冲突。值也默认都会被当做字符串对待。
举例:http://xxx.xxx.com/xx/xx?a=1&b=2
request代码:
import requests url = "http://localhost:8000/test/?a=1&b=2" payload={}headers = {} response = requests.request("POST", url, headers=headers, data=payload) print(response.text)
接口详情:
可以看到,用request.GET['key']的方式可以从请求中提取数据。
二. Headers 中带参数
简介:就是把参数藏在了header中,一般的身份验证参数,如sign,token等有的公司会放在这里。值也默认都会被当做字符串对待。
举例:a=1
requests代码:
import requests url = "http://localhost:8000/test/" payload={}headers = { 'a': '1'} response = requests.request("POST", url, headers=headers, data=payload) print(response.text)
接口详情:
注意到,a=1 被放到了headers中,并且默认首字母变成了大写,后台可以通过request.headers方法可以拿到。
三. 请求体 none
简介:就是什么参数都不传。
requests代码:
import requests url = "http://localhost:8000/test/" payload={}headers = {} response = requests.request("POST", url, headers=headers, data=payload) print(response.text)
接口详情:
注意,此时的content-length 长度 值为0
四. 请求体 form-data ,值也默认都会被当做字符串对待。
简介:就是即想传键值对,又想传文件的时候会使用,系统会随机生成一个字符串叫boundary,用来分割这些键值对参数和文件的。可以传多个文件或键值对。
举例:键值对为:a=1,b=2 文件为:c=1.png,d=README.md
requests代码:
特别注意:requests方法有个特点,如果你本次请求没有带文件,则会默认给你改成x-www-form-urlencoded格式,而不是原来你想的form-data格式。这样的设计其实影响并不是特别大,request.POST方法获取到的结果不会有变化,但是reuqest.body方法的结果则完全不一样了。
如果传了文件,那么一切都是正常的。
这个和postman这种工具的设计并不一样,postman是哪怕你没有传文件,也照样给你按照fom-data的格式传输。requests就会擅自给你改成x-www-form-urlencoded。
requests代码(有文件传输的时候):
import requests url = "http://localhost:8000/test/" payload={"a":"1","b":"2"}files=[ ('c',('1.png',open('/xxx/xxx/1.png','rb'),'image/png')), ('d',('README.md',open('/xxx/xxx/README.md','rb'),'application/octet-stream'))]headers = {} response = requests.request("POST", url, headers=headers, data=payload, files=files) print(response.text)
此时有文件的情况下,会自动生成boundary。
接口详情:
requests代码(无文件传输的时候):
import requests url = "http://localhost:8000/test/" payload={"a":"1","b":"2"}files=[]headers = {} response = requests.request("POST", url, headers=headers, data=payload, files=files) print(response.text)
此时会自动给你转换成x-www-form-urlencoded
如果你执意要在无文件传输的情况下,让requests保持和postman一致,为了防止接口自动化代码背锅,那么以下的算法本文是首创,请立即保存成书签。
import requests url = "http://localhost:8000/test/"boundary = '--------------------------994111054968797846840047' files=[] payload=''payload_old = {"a":1,"b":2}for i in payload_old.keys(): payload += '--%s\r\nContent-Disposition: form-data; name="%s"\r\n\r\n%s\r\n'%(boundary,i,payload_old[i])payload += '--'+boundary+'--\r\n' headers = {'Content-Type':'multipart/form-data; boundary=%s'%boundary} response = requests.request("POST", url, headers=headers, data=payload, files=files) print(response.text)
接口详情:(此时结果和postman完全一致)
五:x-www-form-urlencoded
简介:就是正常传输键值对,不能带文件。值也默认都会被当做字符串对待。
举例:a=1,b=2
requests代码:
import requests url = "http://localhost:8000/test/" payload='a=1&b=2'headers = { 'Content-Type': 'application/x-www-form-urlencoded'} response = requests.request("POST", url, headers=headers, data=payload) print(response.text)
接口详情:
可以通过request.POST方法来获取参数了
------------------ 重复Key情况:
重复的Key在一些接口中也会出现,虽然情况极少。但是一旦出现,你的接口自动化/平台能否处理成功很关键。
如 a=1 & a=2 & b=3
此时无需特殊代码修正,重复的a结果会合并到a中。
但是大家也注意到了,此时若通过["a"]或者.get("a") 方法来获取的a的值,都只是最后一个'2' 。这是因为,QueryDict格式天生就可以处理存储重复key的情况,不会让值损失掉。所以post/get请求的结果都是QueryDict,而并非所谓的字典,字典是不允许重复key的。
那么我们此时自然也不能当做字典的方法去获取里面的值,否则只会拿到最后一个值'2'。
解决方案是,使用QueryDict的专有方法:.getlist('a') ,这样即可拿到a里所有的值(放在了一个列表中)。
比如:
print(request.GET.getlist('a'))
结果:
因篇幅过长,所以本节到此结束,欢迎继续收看 【实测】大白话讲requests发送请求的不同参数类型(下)
点个关注不迷路,公众号:测试开发干货