js blob 文件上传
js中的文件处理和文件上传掌握得更扎实,有更深入的理解,底层原理
ps.项目中使用插件上传
- filereader
- mime类型筛选
- 单文件的2种处理方案
- 多文件&文件上传进度管控
Ajax文件上传时:Formdata、File、Blob的关系-腾讯云开发者社区-腾讯云
Js上传blob_js blob上传_js blob 上传图片 - 腾讯云开发者社区 - 腾讯云
文件上传基础知识
filereader:异步读取和解析文件
通过input-type="file"元素获取到files列表,file对象有3个基础属性:
+name
+size:xxx字节 xxxB
+type: mime类型
缩略图:
FileReader实例读取到base64编码,readAsDataUrl
readAsArrayBuffer:读取到的arraybuffer或者是blob对象,大文件切片上传的时候
上传到服务器-formdata
上传中:有个loading效果
缩略图是:上传到服务器之后服务器上的地址
axios封装
面试时经常问——客户端传给服务器端的格式:
multipart/form-data、application/json、application/x-www-form-urlencoded(表单形式:xxx=xxx&xxx=xxx)、raw(纯文本、json、二进制)=====》MIME类型和请求头配置
待解决服务器:
起一个node服务:用那个库multipart
跨域
javascript - node中multiparty模块使用form.parse解析上传文件时回调函数参数files获取为空对象 - SegmentFault 思否
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件title>
<style>
style>
head>
<body>
<input type="file" id="uploadFile" accept="image/*">
<img src="" alt="" width="100" id="uploadImg">
<script src="./js/axios.min.js">script> <script src="./js/qs.min.js">script> <script> uploadFile.onchange=async function (){ let files=this.files; if(!files.length) return; /** * name * size * type:mime类型 */ // 校验类型:只允许上传图片 let file=files[0]; let {name,size,type}=file; if(!/(jpg|png|jpeg|gif)$/.test(type)) return alert('只能上传jpg|png|jpeg|gif格式') if(size>1024*1024) return alert('文件大小不能超过1MB') console.log('file',file); /** * 缩略图:通过fileReader去读取图片,得到base64编码 */ /*let fileReader=new FileReader() // readAsArrayBuffer 读取成buffer或者blob格式的值。断点续传/切片上传 fileReader.readAsDataURL(file); fileReader.onload=function (ev){ console.log('ev',ev); uploadImg.src=ev.target.result; }*/ /** * 1.form-data方法,把完整的file对象传过去 */ /*let formData=new FormData() formData.append('file',file) formData.append('filename',file.name); console.log(formData,formData.get('file'),formData.get('filename')); let res=await postRequest('/upload1',formData,{headers:{'Content-Type':'multipart/form-data'}}); uploadImg.src=res.path;*/ /** * 2.base64方法 */ let base64=await readBase64(file) let data={ chunk:base64, filename:file.name } let res=await postRequest('/upload2',Qs.stringify(data),{headers:{'Content-Type':'application/x-www-form-urlencoded'}}) uploadImg.src=res.path; } function postRequest(url,data,config={}){ return axios.post(`http://127.0.0.1:8080${url}`,data,config).then(res=>res.data) } function readBase64(file){ return new Promise((resolve,reject)=>{ let fr=new FileReader() fr.readAsDataURL(file) fr.onload=function (ev){ resolve(ev.target.result) } }) } script> body> html>
base64
封装:tree 图片懒加载 modalPlugin 文件上传插件……
文件上传:切片上传 断点续传 文件秒传
多文件
其实和单文件类似
上传进度:
axios: onUploadProgress:function(){}
原生js:onUpload
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件-多个文件title>
<style>
.thumbnail-box{
width: 100px;
height: 100px;
position: relative;
float: left;
}
.thumbnail-box img{width: 100%}
.thumbnail-box .progress{
position: absolute;
bottom: 0;
left: 0;
height: 20px;
width: 0;
background: dodgerblue;
transition: width .3s;
}
.thumbnail-box .mask{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
}
.upload-draggable{
width: 300px;
height: 300px;
line-height: 300px;
background: darkgrey;
font-size: 60px;
display: block;
vertical-align: middle;
text-align: center;
}
style>
head>
<body>
<input type="file" id="uploadFile" accept="image/*" multiple>
<div class="thumbnail">div> <img src="" alt="" width="100" id="uploadImg"> <div class="upload-draggable" contenteditable="true">+div> <script src="./js/axios.min.js">script> <script src="./js/qs.min.js">script> <script> uploadFile.onchange=async function (){ let files=this.files; if(!files.length) return; /** * 缩略图:通过fileReader去读取图片,得到base64编码 */ files=Array.from(files) let base64s=await Promise.all(files.map((file)=>readBase64(file))) let thumbHtml=base64s.reduce((html,base64,index)=>{ files[index].base64=base64 html+=`<div class="thumbnail-box"> <img src="${base64}" alt="" width="100%"> <div class="progress">div> <div class="mask">div> div>` return html; },'') let thumbContainer=document.querySelector('.thumbnail') thumbContainer.innerHTML=thumbHtml let thumbBox=document.querySelectorAll('.thumbnail-box') // 调接口 files.forEach(async (file,index)=>{ console.log(file); let data={ chunk:encodeURIComponent(file.base64), filename:file.name } let thumb=thumbBox[index] let progress=thumb.querySelector('.progress') let mask=thumb.querySelector('.mask') let config={ headers:{ 'Content-Type':'application/x-www-form-urlencoded' }, onUploadProgress:async function (ev){ let prog=Math.ceil(ev.loaded/ev.total*100); // 好像只进来了1次。。。 console.log('prog',prog,ev); progress.style.width=prog+'%' } } console.log(data); let res=await postRequest('/upload2',Qs.stringify(data),config) if(res.code===0){ await delay(1000) progress.style.display='none' mask.style.display='none' } }) } /** * 拖拽上传 * @param seconds * @returns {Promise<unknown>} */ let uploadDraggable=document.querySelector('.upload-draggable') console.log('uploadDraggable',uploadDraggable); uploadDraggable.ondrop=function (ev){ ev.preventDefault() let file=ev.dataTransfer.files; // ev.dataTransfer直接打印竟然没有,但是实际file是有的。。。无语 console.log('ondrop',ev.dataTransfer,file); } function delay(seconds=500){ return new Promise(resolve=>{ setTimeout(()=>resolve(),seconds) }) } function postRequest(url,data,config={}){ return axios.post(`http://127.0.0.1:8080${url}`,data,config).then(res=>res.data) } function readBase64(file){ return new Promise((resolve,reject)=>{ let fr=new FileReader() fr.readAsDataURL(file) fr.onload=function (ev){ resolve(ev.target.result) } }) } script> body> html>
大文件上传
背景:文件比较大,直接传给服务器,导致传输时间过长过程中很容易出现问题;传失败还要重新传还要花这么多时间
思路
实现思路&逻辑:把文件切割成几个切片,不是一次性传给服务器,是一部分一部分传。服务器:可能会新建一个目录,把切片放到这个文件夹下。所有切片传完了,再向服务器发一个请求,服务器把所有把切片统一合并成一起,最后返回合成的文件。
断点续传:一共10个切片,只成功了3个,重新上传时服务器会提供一个接口当前已经上传了哪些切片,告诉我成功的切片。只把剩下7个传给服务器。(即使不提供接口服务器发现切片已经存在了它会立即返回一个成功,再或者就是客户端拉取一下哪些切片已经传了把没传的再传)。主题思路就是传过的就不再传了。
根据文件内容生成hash值
async/await使用try-catch包起来
裁切方式:「固定大小」&「固定数量」
先以固定大小,若裁切的数量太大了超过了最大数量,就改成固定数量
用JavaScript实现文件的上传与下载_js文件上传fileupload_忧郁的蛋~的博客-CSDN博客
代码流程
获取已经上传的切片 /upload_already
裁切大文件,一片一片上传 /upload_chunk。有一个切片传失败了我就停止上传,我就不再传了
都成功,调合并切片的接口 /upload_merge
GitHub - yaogengzhu/uploadFile: 文件上传、form-data方式、base64方式、文件上传进度条管控、多个文件上传、大文件上传(切片上传、断点续传)
GitHub - chinbor/bfu: About how to upload files, especially large files
涉及到的接口
获取已经上传的切片
https://www.cnblogs.com/zhuxianguo/p/11445952.html