基于 原生JS 实现二进制流文件下载,支持下载资源地址的有效性校验;支持文件下载时的 文件进度 信息获取
校验下载资源的地址有效性
-
实现方案
通过
XMLHttpRequest创建同步的HEAD请求,只获取响应头而不需要获取响应体的方式校验请求地址是否有效 -
方法封装
const corsEnabled = url => { const xhr = new XMLHttpRequest() xhr.open('HEAD', url, false) try { xhr.send() } catch (e) {} return xhr.status >= 200 && xhr.status <= 299 }
跟踪下载文件的进度
-
实现方案
第一步:通过响应头
header中的Content-Length和Content-Disposition分别获取完整的响应长度和文件名称第二步:通过流读取器
stream.getReader()循环读取并计算当前下载进度,直到响应体body下载完成第三步:返回所有块字节的
Uint8Array数据chunks和文件名称 -
方法封装
const download = async (url, callback) => { const { ok, status, statusText, headers, body: stream } = await fetch(url, { mode: 'cors', credentials: 'same-origin' }) if (!ok) return Promise.reject({ status, statusText }) const reader = stream.getReader() const totalSize = headers.get('Content-Length') const filename = decodeURI(headers.get('Content-Disposition').split('filename=')[1]) let receiveSize = 0, chunks = [] while(true) { const { done, value } = await reader.read() if (done) break chunks.push(value) receiveSize += value.length callback(Number((receiveSize / totalSize * 100).toFixed(2))) } return Promise.resolve({ filedata: chunks, filename }) }使用
decodeURI()函数对encodeURI()编码过的内容进行解码,解决中文文件名称的乱码问题
实现二进制流文件下载
-
实现方案
第一步:通过
a标签的download属性设置下载文件的名称第二步:通过
a标签的href属性设置下载文件的地址,使用URL.createObjectURL()方法生成一个在内存中指向流文件的引用路径作为文件的下载地址第三步:创建可以
同步执行的自定义事件,通过dispatchEvent进行事件的触发,让事件用于非DOM代码中 -
方法封装
const saveAs = (data, filename) => { const blob = data instanceof Blob ? data : new Blob(data) const node = document.createElement('a') Object.assign(node, { download: filename, href: URL.createObjectURL(blob), }) try { node.dispatchEvent(new MouseEvent('click')) } catch(e) { const evt = document.createEvent('MouseEvents') evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null) node.dispatchEvent(evt) } URL.revokeObjectURL(node.href) }通过 外观模式 解决自定义事件的兼容性
一起学习,加群交流看 沸点