在完成文件上传功能时,通常会选择组件库中写好的upload组件,由于在实际开发中接口存在一些特殊的限制(比如限制请求头,要求携带一些特殊参数),直接使用该组件的action方法会不太方便,所以一般使用upload组件上传文件时一般会选择自定义上传文件,本文以elementui为例。
1.将action置空,并设置auto-upload为false,阻止自动上传
<el-upload
class="upload-demo"
ref="adModel"
drag
action=""
:auto-upload="false"
:on-preview="handlePreview"
:on-error="handleOnError"
:on-success="handleSuccess"
:before-upload="beforeUpload"
:on-change="handleChange"
>
点击上传文件
</el-upload>
2.使用FileReader进行文件读取
- 数据流和文件处理的基本概念
数据流是指
连续的数据序列,可以从一个源传输到另一个目的地。在前端开发中,文件可以被看作数据流的一种形式,可以通过数据流的方式进行处理。
- Blob对象和ArrayBuffer:处理二进制数据流
先放一张经典的图File接口基于Blob,继承了blob的功能并将其扩展使其支持用户系统上的文件。
在前端处理文件时,经常需要处理二进制数据。
Blob(Binary Large Object)对象是用来表示二进制数据的一个接口,可以存储大量的二进制数据。
- FileReader
FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用File或Blob对象指定要读取的文件或数据。其中File对象可以是来自用户在一个
<input>元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的DataTransfer对象,还可以是来自在一个 HTMLCanvasElement上执行mozGetAsFile()方法后返回结果。
通过 FileReader,可以通过异步方式读取文件,并将文件内容转换为可用的数据形式,比如文本数据或二进制数据。
FileReader的实例拥有4个方法,其中3个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能。
| 方法名 | 描述 |
|---|---|
| FileReader.abort() | 中止读取操作。在返回时,readyState 属性为 DONE。 |
| FileReader.readAsArrayBuffer() | 开始读取指定的 Blob 中的内容。 一旦完成,result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象。 |
| FileReader.readAsBinaryString() | 开始读取指定的 Blob 中的内容。一旦完成,result 属性中将包含所读取文件的原始二进制数据。 |
| FileReader.readAsDataURL() | 开始读取指定的 Blob 中的内容。一旦完成,result 属性中将包含一个 data: URL 格式的 Base64 字符串以表示所读取文件的内容。 |
| FileReader.readAsText() | 开始读取指定的Blob中的内容。一旦完成,result 属性中将包含一个字符串以表示所读取的文件内容。 |
一旦成功地读取了文件的内容,就可以将文件流展示在前端页面上。具体的展示方式取决于文件的类型。例如,对于文本文件,可以直接将其内容显示在页面的文本框或区域中;对于图片文件,可以使用<img>标签展示图片;对于音视频文件,可以使用<video>或 <audio> 标签来播放。通过将文件流展示在前端页面上,可以实现在线预览和查看文件内容的功能。
场景一:展示图片,获取图片的base64
const handleChange = (file) => {
imgurl = URL.createObjectURL(file.raw);//可以作为<img>的src展示
const reader = new FileReader();
reader.onload = function (event) {
const [_, content] = event.target.result.split(",");
imgBase64 = content;
console.log("this is imgbase64",imgBase64); //图片base64格式的data URL,可用于文件传输或上传
};
reader.readAsDataURL(file.raw);
};
Object URL又称Blog URL,它是一个用来表示File Object或Blob Object的URL。这里的object参数是用于创建URL的File对象、Blob对象或者MediaSource对象,生成的链接就是以blob:开头的一段地址,表示指向的是一个二进制数据。
场景二:文件上传
1.使用post请求,配置config
headers: { 'Content-Type': 'multipart/form-data' }
一开始我直接将文件的二进制流放进了请求体里,但是看请求发现boundary格式不对,网上查了查发现需要使用FormData。
2.创建FormData
const formData = new FormData();
formData.append(key, value); // 请求参数
formData.append('file', file); // 文件列表
然后就500了,postman上传是ok的,后端提示请求参数不是blob,于是将传的value封装成blob对象。
const formData = new FormData();
reader.onload = function (event) {
const fileBlob = new Blob([event.target.result]);
formData.append("file", fileBlob, fileName.value);
};
reader.readAsArrayBuffer(file.raw);
对于append()方法强烈建议使用三个参数的方法,两个参数传递文件时很容易出错。
至此,后端终于可以正常接收上传的文件了,但是发现文件不能正常打开,问了后端的同事发现他加了类型校验,这里我上传的是压缩文件,需要显示地设置类型。
const fileBlob = new Blob([event.target.result], {
type: "application/zip",
});
这个问题算是解决了,但是感觉还没学透,估计以后还会遇到其它问题。