测试开发实战[提测平台]17-Flask&Vue文件上传实现
微信搜索【大奇测试开】,关注这个坚持分享测试开发干货的家伙。
先回顾下在此系列第8次分享给出的预期实现的产品原型和需求说明,如下图整体上和前两节实现很相似,只不过一般测试报告要写的内容可能比较多,就多用了些多行输入框组件,另外一个特别的全新功能操作就是 附件上传,这是需要先解决和要掌握的重点内容。
后端服务实现附件的保存,要写个上传接口,服务端通过request.files进行获取实现,Postman模拟请求的话,方法使用POST,文件通过form-data格式中的file进行上传,一个基本的实现代码接口如下:
定义请求方法和路径
拼接一个项目保存文件夹的一个绝对路径
获取form-data指定key的文件,通过save保存后返回成功消息
@test_manager.route("/api/report/upload",methods=['POST'])
def uploadFile():
# 保存文件的路径
save_path = os.path.join(os.path.abspath(os.path.dirname(__file__)).split('TPMService')[0], 'TPMService/static')
# 获取文件
attfile = request.files.get('file')
attfile.save(os.path.join(save_path, attfile.filename))
return {"code":200, "message":"上传请求成功"}
这里对于文件上传,一般来说不能无限制上传,需要对格式、大小做一些限制,还要做一些安全的处理,方式是通过FileField做要求如格式的限制,用secure_filename做文件名安全处理
优化后完整的代码分两个片段
1. 引入依赖和做fileForm类
import os
# 涉及的相关依赖引用
from wtforms import Form,FileField
from flask_wtf.file import FileRequired,FileAllowed
from werkzeug.utils import secure_filename
from werkzeug.datastructures import CombinedMultiDict # 表单提交相关校验
class fileForm(Form):
file = FileField(validators=[FileRequired(), FileAllowed(['jpg', 'png', 'gif', 'pdf', 'zip'])])
2. 增加格式校验和安全校验,另外这里需要注意下,我拿的直接是上传文件的名字,我并没有对文件名做一个随机生成处理,这样如果有重名文件再次上传会被覆盖掉,一般作为一个静态资源或者文件服务来说是要做生成唯一码名称,python可以使用uuid,大家可以尝试扩展下,如果是生成自己的串码名还带来另外一个问题,真的是统一文件多次反复上传如何处理,那可能就要做真正的数据文件信息存储,然后做MD5校验,由于我们只是做个简单附件服务,就不再做更多上传服务的讨论了。
@test_manager.route("/api/report/upload",methods=['POST'])
def uploadFile():
# 初始化返回对象
resp_success = format.resp_format_success
resp_failed = format.resp_format_failed file_form = fileForm(CombinedMultiDict([request.form, request.files]))
if file_form.validate():
# 获取项目路径+保存文件夹,组成服务保存绝对路径
save_path = os.path.join(os.path.abspath(os.path.dirname(__file__)).split('TPMService')[0], 'TPMService/static')
# 通过表单提交的form-data获取选择上传的文件
attfile = request.files.get('file')
# 进行安全名称检查处理
file_name = secure_filename(attfile.filename)
# 保存文件文件中
attfile.save(os.path.join(save_path, file_name)) resp_success['data'] = {"fileName": file_name}
return resp_success
else:
resp_failed['message'] = '文件格式不符合预期'
return resp_failed
上边只是实现了文件格式的校验,对于上传限制大小从网上搜的资料来看,flask一般通过全局配置,比如下边是配置限制一个16MB大小的文件限制,如果超过会返回 413 Request Entity Too Large,网上资料说16M也是默认大小,但实际我测试了下,如果不设置全局限制,我传300+M除了慢点也能上传成功,并且搜索了源码 MAX_CONTENT_LENGTH = None,可能是由于版本的原因,现在没有这个限制了。
from flask import Flask, Requestapp = Flask(__name__)app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000
关于Flask文件上传更多的解释和例子请参考 [链接1],还有一种第三方插件也可以对文件进行友好的操作参考 [链接2],不过这两种方式都是全局控制的,如果想不同的接口单独控制大小,目前尝试的方式是读取文件然后获取长度 len(attfile.read()) 其实就是字节大小,对其进行比较返回即可,如果你有更好的方案,记得告诉我。
上传文件接口搞定了,自然少不了下载接口,这个比较简单,通过flask提供的send_from_directory方法实现,代码如下,详细解释参考 [链接1] 后半部分。
from flask import send_from_directory @test_manager.route("/api/file/download",methods=['GET'])
def downloadFile():
fimeName = request.args.get('name') # 保存文件的相对路径
save_path = os.path.join(os.path.abspath(os.path.dirname(__file__)).split('TPMService')[0], 'TPMService/static') result = send_from_directory(save_path, fimeName) return result
重启后端服务后,用postman请求做个上传测试,效果如图,一开始是个超大提示,后来正常上传返回结果成功。
刷新查看代码服务存储位置,文件已经正确上传
下载的测试可以通过浏览GET请求服务+路径 /api/file/download?=文件名 进行下载验证。
前端Vue的实现,用到的组件是“Upload上传”,官网给出了多种样式和方式,比如多文件,头像上传,拖拽上传,列表形式等等,具体可参考 [链接3]。
如图其中action就是上传地址,这块就可以替换成刚刚实现的上传接口 http://127.0.0.1:5000/api/report/upload 表示上传地址,默认为选择文件后自动上传,其实就是帮助你实现postman演示的表单文件自动提交,可以通过:auto-upload="false" 设置关闭,也可以通过 http-request 覆盖默认的上传行为自定义实现。
这两种方式都会实际写个Demo实践下
1. 自动上传 新建一个文件上传页面,路由绑定到跟目录,编写<template>和<script>部分代码,这里在方法中用 :on-success 钩子打印下上传成功的返回信息
<template>
<div class="app-container">
<el-form>
<el-form-item label="附件" prop="test_file">
<el-upload
:limit="1"
:file-list="fileList"
:auto-upload="true"
action="http://127.0.0.1:5000/api/report/upload"
:on-success="uploadFile"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png/zip/pdf文件,且不超过1M</div>
</el-upload>
</el-form-item>
</el-form>
</div>
</template> <script>
export default {
name: 'DemoUpload',
data() {
return {
fileList: []
}
},
methods: {
uploadFile(response, file, fileList) {
console.log(response)
console.log(file)
console.log(fileList)
}
}
}
</script>
启动前后端,选择一个小于10M的文件进行上传测试,可以看到正常返回2000,并且能正常拿到钩子中三个参数信息,后边报告功能实现其实就是拿到返回的文件名赋值给一个变量即可。
再测试一种情况,文件格式不符合要求,大小超出服务端限制,发现在文件不符合格式的情况是40000,但文件列表还是显示了,做个优化处理,在状态码不正确的情况,清空filelist
还有另外一个问题就是服务端大小超限制的时候回返回403,但element vue 及upload 直接在返回的时候时候拦截处理了,所以没办法精细异常处理,就进行了模糊提示处理。优化后及 增加了 :on-success 使用的方式的代码如下:
<template>
<div class="app-container">
<el-form>
<el-form-item label="实现一" prop="test_file">
<el-upload
ref="fileOne"
:limit="1"
:file-list="fileList"
:auto-upload="true"
action="http://127.0.0.1:5000/api/report/upload"
:on-success="uploadSuccess"
:on-error="uploadErrors"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png/zip/pdf文件,且不超过10M</div>
</el-upload>
</el-form-item>
<el-form-item label="实现二" prop="test_file">
<el-upload
:limit="1"
:file-list="fileList"
action="http://127.0.0.1:5000/api/report/upload"
:http-request="uploadeFile"
:on-success="uploadSuccess"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png/zip/pdf文件,且不超过10M</div>
</el-upload>
</el-form-item>
</el-form>
</div>
</template> <script>
import axios from 'axios' export default {
name: 'DemoUpload',
data() {
return {
fileList: [],
fileNanme: ''
}
},
methods: {
uploadSuccess(response, file, fileList) {
if (response.code === 40000) {
this.$message({
message: '格式不正确或者上传异常',
type: 'warning'
})
this.fileList = []
} else {
this.$message({
message: '上传成功',
type: 'success'
})
}
},
uploadErrors(err, file, fileList) {
this.$message({
message: '大小不符合要求或服务器异常',
type: 'warning'
})
},
uploadeFile(params) {
console.log(params.file)
const fd = new FormData()
fd.append('file', params.file)
fd.append('FileName', params.file.name)
fd.append('async', true)
const config = {
headers: { 'Content-Type': 'multipart/form-data' }
}
axios
.post(params.action, fd, config)
.then(res => {
console.log(res.data)
})
.catch(Error => {
this.fileList = []
this.$message({
message: '大小不符合要求或服务器异常',
type: 'warning'
})
})
}
}
}
</script>
为什么有了自动上传还是要讲个自定义上传,这里有两点:
目前为止校验都依赖后端,但实际上服务端校验是一个后置校验,文件已经上传了,如果文件大或者量大会很占用IO,所以可以自定义提交进行一些前端的上传校验。
作为实践尽量为大家趟一下坑 :on-success的使用官方并没有给出例子,而要拿到组件信息经过验证是通过参数方法参数获取,如下边红色框圈出的一些重要信息。
再做一个异常的情况下的上传测试,这是由uploadErrors钩子 或者 axios catch(error)捕获实现。
到此本篇的分享大概是这些内容,下一次将组合完成报告部分,也就是【提出平台】的第一阶段,顺便也会公布下上次调查结果,以及一些后续安排,欢迎大家持续关注和交流,方式可以通过私信或者公众号联系加微信入群均可。
【参考链接】
[链接1] https://dormousehole.readthedocs.io/en/latest/patterns/fileuploads.html
[链接2] https://pythonhosted.org/Flask-Uploads/
[链接3] https://element.eleme.io/#/zh-CN/component/upload
坚持原创,坚持实践,坚持干货,如果你觉得有用,请点击推荐,也欢迎关注我博客园和微信公众号。
测试开发实战[提测平台]17-Flask&Vue文件上传实现的更多相关文章
- 测试开发实战[提测平台]20-图表G2Plot在项目的实践实录
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. G2Plot项目应用 上一篇<提测平台19-Echarts图表在项目的实践>讲解了Echarts的图表应用,此篇来看下开箱即用 ...
- 测试开发实战[提测平台]19-Echarts图表在项目的应用
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 在图表统计展示方面,笔者目前使用过的两种开源,分别是 Echats 和 G2Plot 组件,从个人使用上来讲前者应用更广.自定义开发更灵活 ...
- Element Vue 开箱即用框架如何使用-测试开发【提测平台】阶段小结(二)
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 上一篇总结了后端服务接口的开发,这篇我们主要来总结下前后端分离开发中的前端部分,主要是开箱即用的框架介绍和之前章节组件的梳理和部分的扩展内 ...
- 测试开发【提测平台】分享13-远程搜索和路由$route使用实现新建提测需求
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本篇继续提测平台开发,按惯例先给出学习的思维导图,以便快速了解学习知识和平台功能实现的重点. 基本知识点学习 远程搜索 显示的数据通过输入 ...
- iOS开发之网络编程--使用NSURLConnection实现文件上传
前言:使用NSURLConnection实现文件上传有点繁琐. 本文并没有介绍使用第三方框架上传文件. 正文: 这里先提供用于编码测试的接口:http://120.25.226.186:3281 ...
- flask完成文件上传功能
在使用flask定义路由完成文件上传时,定义upload视图函数 from flask import Flask, render_template from werkzeug.utils import ...
- Flask入门文件上传flask-uploads(八)
1 视图传递多个参数 (1) 普通传参 : 关键字参数传递 return render_template('模板名称.html',arg1=val1,arg2=val2...) (2) 字典传参 : ...
- Spring Boot 2.x(十六):玩转vue文件上传
为什么使用Vue-Simple-Uploader 最近用到了Vue + Spring Boot来完成文件上传的操作,踩了一些坑,对比了一些Vue的组件,发现了一个很好用的组件--Vue-Simple- ...
- iOS开发之结合asp.net webservice实现文件上传下载
iOS开发中会经常用到文件上传下载的功能,这篇文件将介绍一下使用asp.net webservice实现文件上传下载. 首先,让我们看下文件下载. 这里我们下载cnblogs上的一个zip文件.使用N ...
随机推荐
- Java 单例模式大乱斗
1. 饿汉模式 线程安全 public class SingleInstance1 { private static SingleInstance1 single=new SingleInstance ...
- 5、使用ZSetOperations(有序)操作redis(Zset有序集合)
文章来源:https://www.cnblogs.com/shiguotao-com/p/10564454.html 方法 c参数 s说明 void set(K key, V value); ke ...
- Python系列教程-详细版 | 图文+代码,快速搞定Python编程(附全套速查表)
作者:韩信子@ShowMeAI 教程地址:http://showmeai.tech/article-detail/python-tutorial 声明:版权所有,转载请联系平台与作者并注明出处 引言 ...
- 【Vue.js】SPA
SPA 2019-11-13 23:20:48 by冲冲 1.概念 (1)MPA(multi-page application) 特点:每一次页面跳转的时候,后台服务器都会返回一个新的html文档 ...
- PCA方差解释比例求解与绘图?
目录 主成分方差解释率计算 绘图示例 主成分方差解释率计算 通常,求得了PCA降维后的特征值,我们就可以绘图,但各个维度的方差解释率没有得到,就无法获得PC坐标的百分比. 有些工具的结果是提供了维度标 ...
- PHP非对称加密-RSA
对称加密算法是在加密和解密时使用同一个密钥.与对称加密算法不同,非对称加密算法需要两个密钥--公开密钥(public key)和私有密钥(private key)进行加密和解密.公钥和密钥是一对,如果 ...
- 毕业设计之zabbix集合
lnmp环境请查看https://www.cnblogs.com/betterquan/p/12285956.html 但是!!!注意php的编译: https://www.zabbix.com/do ...
- arm三大编译器的不同选择编译
ARM 系列目前支持三大主流的工具链,即ARM RealView (armcc), IAR EWARM (iccarm), and GNU Compiler Collection (gcc). ...
- Excel-同个工作簿中,多个工作表中有格式一致的表格,做汇总透视合并信息
12.同个工作簿中,多个工作表中有格式一致的表格,做汇总透视合并信息 在工作簿中新建一个工作表-汇总表->按Alt+D+P调出数据透视表和数据透视图向导->选择"多重合并计算数据 ...
- 3步!完成WordPress博客迁移与重新部署
本文来自于轻量应用服务器征文活动的用户投稿,已获得作者(昵称nstar)授权发布. 由于现有的服务器已经到期,并且活动已经取消,续费一个月145元比较贵,于是参加了阿里云的活动购买一台轻量应用服务器. ...