该文原创为新潮质量保障技术团队中的 “上进的中年软件测试从业者”,用于技术交流分享

开篇

之前有聊过说早上的时间很宝贵,不要轻易浪费。最近又一次深刻体会到需要认真对待上午这段短暂的时间。它是你一天之中最大脑最清醒,思路最敏捷。就像是计算机运算查找文件一样,早上查找文件的速度是云计算,到了晚上恐怕就是 286 的老机器了。

昨天晚上在公司等开发提测,也没什么能帮得上的,就打算自己静下心来写一下这篇,结果脑子里一团浆糊,完全没有任何思路来梳理这篇文章。尝试了三次最终都废弃掉了。今天打算利用早上的时间写一下,结果写了不到 100 个字,开发解决了 block 的问题又开始新一轮测试。现在测完准备上线了,好在今天的状态不错,可以继续写一点。

背景

在软件测试过程中,经常需要处理一些文件,如 testlink 用例生成工具,敏捷开发过程排期表自动生成任务等。这里就会涉及到两种文件处理场景:

- 文件上传

- 文件下载

实现

文件上传

对于文件上传过程,相对来说比较容易实现。可以直接利用 MongoEngine 自带的 FileField 来实现,非常的简单粗暴。当然如果看了我们上期写的 flask_admin 支持重写字段特性的介绍,应该知道还有另外一种实现方式,我们这里就不过多的介绍了。对于 FileFileld 来实现文件的上传,具体过程如下:

- model:
excel_file = FileField(db_field="excel_file", verbose_name=u"用例Excel文件", help_text=u"上传的用例excel文件,文件格式请参考前面成功的记录")
- view: 可以什么也不需要做
- Controller: 只需要 view 的 on_model_change 方法里面加上你要进行的逻辑操作即可
- 效果:


文件下载

对于文件下载来说,我们第一个想到的也是采用 FileField 类型来承载文件,只是需要调查文件的生成和获取过程来实现。

通过调查,我们发现文件生成入库过程如下:

通过 model FileField 支持的 put 方法来生成 MongoEngine GridFS 的二进制数据。

model.xml_file.put(open(xml_file_path, "rb"), content_type="application/x-gtar",
filename=".".join(
model.excel_file.name.split(".")[:-1]) + ".tgz") # 命名压缩包文件与excel一致,替换后缀名为.tgz'

通过 gridfs.GridFS.get 来获取二进制数据,并 read 的方式返回给 Response.
pk = request.args.get('id')
coll = request.args.get('coll')
db = request.args.get('db', 'default')
if not pk or not coll or not db:
abort(404)
fs = gridfs.GridFS(get_db(db), coll)
data = fs.get(self.object_id_converter(pk))

根据上面的方式,我们实现了文件的生成和下载,但是出现了如下的问题:
- 下载后的文件名未知
- 下载为中文文件名时报错

问题解决

下载后的文件名未知

根据以往的经验和抓包,定位到请求文件下载时文件头的 Content-Disposition 有问题,可以通过加上 attachment;filename=${文件名}的方式解决。然后就出现了新的问题,中文文件名无法下载。

下载为中文文件名时报错

具体的报错信息为编码错误,那很容易直接在网上就搜到了解决方案,强制加上 utf-8 的编码即可实现,最终的 Response 部分组成如下:

return Response(data.read(),
content_type=data.content_type,
headers={'Content-Length': data.length,
"Content-Disposition": "attachment;filename*=UTF-8''%s" % quote(
data.name.encode('utf-8'))}) # 解决下载文件名为空的问题, 同时解决中文名下载报错的问题。

结语

昨天晚上强制尝试了三次来写这篇内容,但是实在是坚持不下去,脑子完全是乱的。今天虽然和昨天的状态差不多,但是唯一不同的是项目测试完成已经准备上线了,心理少了一份焦虑。流年不利,祝安好!


↙↙↙阅读原文可查看相关链接,并与作者交流