接口测试中,上传文件的测试场景非常常见。例如:上传头像(图片)、上传文件、上传视频等。
下面以一个上传图片的例子为大家讲解如何通过 python 测试上传文件接口。
①首先通过抓包
分析上传文件接口的请求参数
:
②下面是上传文件接口脚本。
把目标文件以open打开,然后存储到变量file。并且使用
files
参数指明请求的参数名称、上传文件的类型、以及上传文件的路径。
content-type参数,如果我们通过form-data的方式上传文件,我们发送post请求的时候,headers这个参数中一定不能要包括这个值;
即不需要包括
{
"
Content-Type
"
:
"
multipart/form-data
"
}
,例如:
requests库会自动添加这个元素
{
"
Content-Type
"
:
"
multipart/form-data
"
}
;加了反而会报错,从而导致请求不成功。
在前端允许和支持上传的所有格式文件中,当
选择不同格式文件时对接口发起请求
时,
Form Data会自动识别文件的Content-Type【根据传入的文件格式自动解析为headers中的Content-Type】以及Content-Disposition【该字段中包括接口的传参类型(例如下图的form-data),传入文件名(例如下图的filename)等】
。
requests请求接口上传文件代码示例:
import requests
from utils.LogUtil import my_log
from faker import Faker
log=my_log()
faker = Faker('zh_CN')
class marketCreate():
def loginToken(self,mobile,code):
登陆、注册接口
:param mobile: 手机号
:param code: 验证码
:return:
url='http://api.xxxxxx.net/v1/user/loginOrRegister' #登陆接口请求地址
headers={'Content-Type': 'application/json'} #请求头信息,json数据类型
json={"code":code,"deviceId":"5de548ad0e268bc0","deviceName":"HWNXT","mobile":mobile,"mobilePrefix":"63","version":"39"} #请求数据
r=requests.post(url,headers=headers,json=json) #发送请求
token=r.json()['data']['userVO']['token'] #获取token
log.info('手机号'+mobile+'的token值为:'+token) #打印日志
return token #将token返回出去
def uploadimages(self,mobile,file_path,filename):
上传图片接口
:param mobile: 手机号
:param file_path: 文件路径
:param filename: 文件名称
:return:
token = self.loginToken(mobile=mobile, code='789789') #请求登陆接口,获取token
url='http://api.xxxxxx.net/v1/upload/images' #上传文件接口请求地址
headers={'token': token} #请求头信息关联token。不需要赋值Content-Type,requests库会帮忙添加这个元素,加了可能会报错。
file_data={'file':(filename,open(file_path,'rb'),'image/jpeg')} #重点:上传文件请求数据。
r=requests.post(url=url,headers=headers,files=file_data) #发送请求
print(r.json()) #打印响应结果
if __name__ == '__main__':
m=marketCreate()
# 测试,输入手机号、文件地址、文件名称信息;
m.uploadimages(mobile='639266558329',file_path='D:pyCharm_workcmkjProjectdatamarket.jpg',filename='123456.jpg')
执行结果:
C:Python38python.exe D:/pyCharm_work/cmkjProject/page/marketPage.py
2020-01-02 13:48:09,580-D:pyCharm_workcmkjProjectutilsLogUtil.py-INFO-手机号639266558329的token值为:ba9b4f622fa4d6461523870c0d00df46
{'code': 0, 'data': '/group1/M00/00/00/rBDKPF4NhE-ABIFmAAGhT9tm-NA158.jpg', 'success': True}
Process finished with exit code 0
如果需要发送文件到服务器,比如上传图片、视频等,就需要发送二进制数据。
一般上传文件接口的请求头中
定义传入参数数据的媒体类型
使用的都是
Content-Type: multipart/form-data;
数据类型,可以发送文件,也可以发送相关的消息体数据。
POST一个多部分编码(Multipart-Encoded)的文件
使用 requests 上传文件的基本步骤
构造文件数据,通过 open 函数以二进制方式打开文件
构造相关数据
发送请求,将文件数据以files参数传入,其他消息体数据通过data、json、headers、cookies传入
url = 'http://httpbin.org/post' # 上传文件接口
files = {
'file': ('test.png', # 文件名称
open('../file/test.png', 'rb'), # 文件路径
'image/png', # 文件类型
{'Expires': '0'} # 其他参数,非必传
} # => 打开上传文件并且加入文件相关参数
data = {
"name": "test"
# data传入请求参数dict,files传入待上传文件参数dict
r = requests.post(url, data=data, files=files)
print(r.json())
files参数字典里的
file
键名称是根据
上传组件的name属性
来改变的,不一定是file。
【抓包时可以通过请求体中的
binary
行的参数名
获取name属性】
如下图上传组件,当你上传一张图片时,抓包可以发现会传两个值,一个是fileField,一个是type,所以你的文件数据dict要包含 ‘fileField’和‘type’两个key
files = {
'fileField': ('test.png', # 文件名称
open('../file/test.png', 'rb'), # 文件路径
'image/png', # 文件类型
{'Expires': '0'} # 其他参数,非必传
'type': 1
} # => 打开上传文件并且加入文件相关参数
Python使用requests库发送上传zip类型文件的post请求
第一步,通过chrome浏览器的开发者工具,获得发送的参数。
第二步,编写python代码
使用request库的post方法。注意的是要添加files参数,例如:
files ={'app_filename':open('portal-1.0-SNAPSHOT-fat.jar.zip','rb')}
zip压缩包的content-type是application/x-zip-compressed,其他的文件的content-type是application/octet-stream。
①
app_filename
是
F12工具里抓出来的from data里的标有{binary}这一行的参数名【可以理解为name属性】。
②
portal-1.0-SNAPSHOT-fat.jar.zip
是本地电脑zip文件名。(需要请求接口的文件)
③
rb
是读取二进制文件。因为form data媒体类型表示文件是以二进制形式上传。
④
其余的常规参数,放到data参数里
。例如上图的
image_name:fff
就是常规参数。
⑤在接口请求的请求头里注意添加
cookies
或者
Authorization
,(这里测试的网站用的是Authorization验证用户身份。如果没有该参数或者该参数错误或过期,会返回401)。
⑥完整代码如下:
path = os.path.split(os.path.realpath(__file__))[0]
url = host + '/dashboard/cicd/images'
headers = {
'Authorization':'6bae7b70-8dae-4f74-9631-680b9501b52',
'cookie': "_ga=GA1.3.733851079.1534745675; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1537859803; _ga=GA1.3.733851079.1534745675; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1537859803",
datat = {'image_name': 'abcd',
'image_description': 'ccccvcc',
'image_label': '1cc1fcc',
'basic_image': 'openjdk:10',
'store_path': '/opt/app/lzw/'}
files = {'app_filename': (
'portal-1.0-SNAPSHOT-fat.jar.zip', open(os.path.join(path, 'portal-1.0-SNAPSHOT-fat.jar.zip'), 'rb'),
'application/x-zip-compressed')}
# files ={'app_filename':open('portal-1.0-SNAPSHOT-fat.jar.zip','rb')} 和上面的功能一样
result = requests.post(url, files=files, data=datat, headers=headers)
r1 = result.text
print(result.text)
Python使用requests库发送上传excel文件的post请求
zip压缩包的
content-type
是
application/x-zip-compressed
;
其他的文件的
content-type
是
application/octet-stream
。如上图二【直接点击(view source)】
(图一是点击(view parsed即解析后的表单内容)
添加files参数:
files = {'files': (file_name, open(get_file_path(filename=file_name), 'rb'))}
①
files
是
F12工具里抓出来的from data表单数据请求体里的标有
binary
这一行的参数名【可以理解为name属性】。【如图一中的粗红线框出来的文件参数】
②
file_name
对应需要
上传文件的文件名
。
③
open
函数是为了获取
需要上传的文件的流
。
④
rb
是读二进制文件。因为请求头中的
content_type
字段标识
form data
数据媒体类型即表示文件是以二进制形式上传。
⑤其余的常规参数,放到data参数里。
【如上图中的细红线框出的常规参数,即作为同文件上传时还有需要一起上传的body体数据】
代码如下:
def clue_add():
file_name = 'create_club.xls'
files = {'files': (file_name, open(get_file_path(filename=file_name), 'rb'))}
url_upload = 'http://gasst-uat.test.geely.com/cafe.portal-service/frame_center/common/attachmentChunkUpload'
headers = {'Cookie': ReadConfig().read_config('project_GHelper', 'token')}
data_upload = {
'fileName': 'create_club.xls',
'chunkCount': 1,
'chunkIndex': 1
r_upload = requests.post(url=url_upload, files=files, headers=headers, data=data_upload)