hanmk

最近在写脚本时有一个功能是上传附件,也趁这个机会学习了下对于上传文件类的接口该如何进行传参

本次介绍2种方式来上传附件:一种是通过jmeter;另一种是通过python的requests库

接口参数分析

在讲具体方法之前,先来分析下这次上传附件接口的headers与携带的参数信息

headers种主要看content-type,这个请求中的content-type如下

content-type: multipart/form-data; boundary=----WebKitFormBoundaryKtD3qxHwCR9S9Wdy
 
 
 查了一些资料,大概意思是说:数据以multipart/form-data编码,boundary 用于分割不同的字段
继续看下参数是如何的,可能就理解上面说的boundary用于分割字段是什么意思了,chrome控制台下显示的参数信息如下
 
------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还得再研究研究

分类:

技术点:

相关文章: