前言
在日常工作中,文件上传是一个非常常见的功能。在项目开发中,我们通常都会使用一些成熟的上传组件来实现对应的功能。
一般来说,成熟的上传组件不仅会提供漂亮的UI或好的交互体验,但是对于一些文件小的上传方式是可以满足的,那么如果文件过大呢就有点满足不了。
那么接下来我们一起来看看,如何实现大文件的上传吧,由于内容比较多,可能会分几篇文章进行描述,今天会详细简述如何优雅判断文件的上传格式。
实现
我们先来实现简单的上传功能。
创建html文件,使用input的file文件进行文件获取,使用button点击进行上传操作。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>文件上传</title> </head> <body> <div id="warp" style="height: 100px; border: 4px dashed #eee; text-align: center; line-height: 100px;"> <input type="file" id="file"> </div> <button id="btn">上传</button> </body>创建js文件,获取指定元素加入方法。
const fileEle = document.getElementById('file') const btnEle = document.getElementById('btn') let file = null // 文件流 fileEle.addEventListener('change', function (e) { file = e.target.files[0] }) async function uplodaFile(params) { if (await isImage(file)) { console.log('文件格式正确') } else { console.log('文件格式不对') } } btnEle.addEventListener('click', async function (e) { e.preventDefault() uplodaFile() })编写isImage函数使用文件转换二进制的方式来判断文件格式,这样可以很好的避免恶意文件。
// 文件流转换二进制 function blobToString(blob) { return new Promise(resolve => { // 读取文件流 const reader = new FileReader() reader.onload = function () { // 文件截取并转换charCodeAt在进行16进制转换拿到文件的二进制 const ret = reader.result.split('') .map(v => v.charCodeAt()) .map(v => v.toString(16).toUpperCase()) .join(' ') resolve(ret) } reader.readAsBinaryString(blob) }) } // 判断文件是不是jpg的,分别取文件流二进制的前2个和后2个 async function isJpg(file) { const len = file.size const start = await blobToString(file.slice(0, 2)) const tail = await blobToString(file.slice(-2, len)) const isJpg = (start == 'FF D8') && (tail == 'FF D9') return isJpg } // 判断文件是不是gif的,取文件二进制的前6个 async function isGif(file) { const ret = await blobToString(file.slice(0, 6)) return isGIf = (ret == '47 49 46 38 39 61') || (ret == '47 49 46 38 37 61') } // 判断文件是不是png的,取文件二进制的前8个 async function isPng(file) { const ret = await blobToString(file.slice(0, 8)) return isPng = ret == '89 50 4E 47 0D 0A 1A 0A' } // 判断文件 function isImage(file) { return isJpg(file) || isGif(file) || isPng(file) }为了实现更好的体验,我们在加入拖拽上传的功能。
const warpEle = document.getElementById('warp') // 拖拽 fileEle.addEventListener('drop', e => { e.preventDefault() file = e.dataTransfer.files[0] warpEle.style.borderColor = '#eee' }) // 拖拽进入 fileEle.addEventListener('dragover', e => { warpEle.style.borderColor = 'red' e.preventDefault() }) // 拖拽离开 fileEle.addEventListener('dragleave', e => { warpEle.style.borderColor = '#eee' e.preventDefault() })
结语
如果是pdf文件,普通的上传文件组件如果修改pdf后缀改为png或者jpg就可以上传成功,这种是比较危险,如果是恶意文件就会导致程序出现问题,转换二进制的方式不管怎么修改文件后缀文件流信息不变,就会上传不成功,这样就有效限制文件格式了。
为了用户体验我们还加入了文件拖拽上传的功能。这样的话,文件上传 + 拖拽文件上传 + 文件上传格式的校验我们就做完了。
目前的文件上传还是有一定的问题,比如文件名称如果一样怎么限制,文件过大断网怎么上传,所以下一篇我们讲解文件名称转换MD5值进行上传。
xdm,尽情期待吧。