有赞技术 有赞coder



文件上传杂谈_Java作者:陈晓斌部门:增长中心

一、写在前面

文件上传是前端很常见的一类场景。图片、视频和文档等等都属于文件范畴,每个文件则是通过 File.Type 进行更细的划分。本文将针对文件上传的一些通用维度场景做简单的剖析和尝试,抛砖引玉,希望共同学习,共同成长。

本文案例里使用的组件来源于组件库 zent@7.4.4

二、常见的上传场景及实现

上传的形式或场景各式各样,除了业务级别的封装外,常遇到的通用场景有如下:

  • 重复上传

  • 上传预览

  • 拖拽上传

  • 上传裁剪

  • 上传进度可视化

  • 文件压缩

  • 上传前置校验

  • 切片上传

  • 上传加密

  • 暂停&断网续传 ...

我们抽取部分场景进行实现:

2.1 上传前置校验

在文件上传前,经常会需要对文件格式进行校验,我们需要在文件上传/展示预览图前提示用户图片是否完成校验。
常用的格式校验:文件类型文件大小上传的尺寸
我们先看看和文件相关的两个对象的定义:BlobFile
/** A file-like object of immutable, raw data.Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system. */interface Blob {    readonly size: number;    readonly type: string;    arrayBuffer(): Promise<ArrayBuffer>;    slice(start?: number, end?: number, contentType?: string): Blob;    stream(): ReadableStream;    text(): Promise<string>;}
/** Provides information about files and allows JavaScript in a web page to access their content. */interface File extends Blob {    readonly lastModified: number;    readonly name: string;}
通过定义我们知道, Blob是一个不可变、存储文件原数据的一个类文件,但其并非是JS的原生数据,而 File继承于 Blob,使得 Blob信息扩展为用户操作系统可支持的文件,并使得页面里可以使用 Javascript访问其文件信息。

除了继承与原有的 sizetype 属性, File对象还额外返回 lastModified(返回文件最后修改日期)和 name (文件名)属性。以下是某个文件的 File实例信息
{  lastModified: 1581424451211  lastModifiedDate: Tue Feb 11 2020 20:34:11 GMT+0800 (中国标准时间)  name: "计算机网络.pdf"  size: 70809807  type: "application/pdf"  webkitRelativePath: ""}
通过上面信息,我们可以很轻松地校验文件类型文件大小。具体的实现我们接着看下去。

2.1.1 限制文件上传类型

1.使用 input 自带属性 accept Mime 类型列表



属性描述例子
accept期望文件类型image/* , audio/* , video/* ...image/jpeg ...

文件上传杂谈_Java_02

图1 Input限制上传类型

2.使用文件后缀或 MIME-TYPE
// ...const acceptTypes = ['image/png', 'image/jpeg'];const picSlipt = name.split('.');// 切割文件名后缀const picSuffix = `image/${picSlipt[picSlipt.length - 1]}`;// 直接使用解析的文件信息const fileType = file.type;if (acceptTypes.includes(picSuffix) || acceptTypes.includes(fileType)) {  console.log('通过文件类型校验!');};//...
3.使用二进制文件信息流读取
但我们知道直接更改文件后缀并不会改变文件类型的本质。比如以下我直接更改一张 png 图片后缀为 jpg,那么它就很有可能绕过了我们的规则 image/jpeg(虽然想要绕过前端的规则校验有非常多的方法)文件上传杂谈_Java_03

图2 通过更改png图片后缀绕过前端上传规则

但实际上它还是png图片,我们可以通过图像信息查询网站可以得出该图片信息实际如下:文件上传杂谈_Java_04


图3 后缀和类型不一致

上传校验的绕过会给服务器带来很多潜在危险,因此我们可能需要通过更严格的类型校验:文件头信息进行格式鉴别