最近在写脚本时有一个功能是上传附件,也趁这个机会学习了下对于上传文件类的接口该如何进行传参
本次介绍2种方式来上传附件:一种是通过jmeter;另一种是通过python的requests库
接口参数分析
在讲具体方法之前,先来分析下这次上传附件接口的headers与携带的参数信息
headers种主要看content-type,这个请求中的content-type如下
content-type: multipart/form-data; boundary=----WebKitFormBoundaryKtD3qxHwCR9S9Wdy |
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy Content-Disposition: form-data; name="type" 3 ------WebKitFormBoundaryKtD3qxHwCR9S9Wdy Content-Disposition: form-data; name="file"; filename="test.jpg" Content-Type: image/jpeg ------WebKitFormBoundaryKtD3qxHwCR9S9Wdy-- |
可以看到消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary
开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制);
如果传输的是文件,还要包含文件名和文件类型信息;
消息主体最后以 --boundary--
标示结束;
另外boundary每次都是随机生成的!!!
更多内容请看:https://imququ.com/post/four-ways-to-post-data-in-http.html
1. jmeter上传附件
以我这个请求为例,来说明一下如何填写请求参数,先把请求body再次放在在这里
------WebKitFormBoundaryKtD3qxHwCR9S9Wdy Content-Disposition: form-data; name="type" 3 ------WebKitFormBoundaryKtD3qxHwCR9S9Wdy Content-Disposition: form-data; name="file"; filename="test.jpg" Content-Type: image/jpeg ------WebKitFormBoundaryKtD3qxHwCR9S9Wdy-- |
如果请求body中除了需要上传文件外,还需要上传其他参数,如上面的第一部分,表示有个参数名为"type",它的值为3,需要把它填入jmeter的【参数】中
在【文件上传】中填写附件的参数信息
(1) 勾选【对POST使用multipart/form-data】
(2) 文件名称:附件绝对路径
(3) 参数名称:这个根据你在chrome控制台看到参数名称来填写,回头看上面贴出来的请求body
第二部分就是对上传文件的文件名和文件类型的描述,观察内容可以发现
name=“file”,所以这里的参数名称就填写“file”(填错的话,一般会报错的)
Content-Type为image/jpeg,所以jmeter中的MIME类型就填写“image/jpeg”
ps.关于headers的一点说明:刚开始的时候,我一直想着在信息头管理器中加上固定的 content-type: multipart/form-data; boundary=----WebKitFormBoundaryKtD3qxHwCR9S9Wdy
但是实际运行脚本时总是报错,查看结果树中的请求头,也并不是自己定义的这个boundary,貌似自己生成了一个boundary
后来把请求头中的content-type去掉后,再次运行就成功了
综上,在jmeter中进行文件上传的请求脚本就写好了
2. 使用python的requests库上传文件
在使用requests上传文件时,可以先看看官方文档的一段描述:
https://requests.readthedocs.io/zh_CN/latest/user/quickstart.html#post-multipart-encoded
Requests 使得上传多部分编码文件变得很简单:
>>> url = 'http://httpbin.org/post' >>> files = {'file': open('report.xls', 'rb')} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
你可以显式地设置文件名,文件类型和请求头:
>>> url = 'http://httpbin.org/post' >>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
通过这个例子,可以知道requests上传文件是通过files关键字来完成的:先定义一个变量files,它是一个字典,key=file,value则是打开的二进制文件;然后发送post请求时,带上file参数即可
拿我这次的请求来说,如下
files = {"file": ("/data/image/test.jpg", 'rb'))} payload={
type: 3 } response = requests.post(url, files=files, data=payload, headers=headers)
payload中定义的是请求body中的type参数;files是本次要上传的文件;
发送post请求时,需要用files关键字发送文件,用data关键字发送payload
执行这段脚本能够得到和jmeter同样的结果
接下来查看下发送出的请求携带的请求头是什么样的
print(response.request.headers)
结果如下
{ 'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive','Content-Length': '110824', 'token': 'sImDk2YzBkOTkzNFwiLFwiZW1haWxcIjpcIjgxZjcwZjJkOWFmODA1MD', 'Content-Type': 'multipart/form-data; boundary=59a681a11824f2dd578becdd4195cf9b' }
可以发现,python自己给它补全了Content-Type,并且boundary也是自己生成的一段字符
至于如何自己定义boundary还得再研究研究