一个本以为很简单的需求:
后端提供文件的url,前端实现下载!
你会怎样实现?相信很多人都会选择<a>标签, 再加上 h5 提供的 download属性。我也照做了 !!!!!但结果呢?
<a download="资信证明.pdf" thref="http://localhost:57483/App/templateFile/05.pdf">下载测试</a>
结果,对于image、pdf、js等文件,是在浏览器中直接打开预览的方式,而非下载。
因为这些文件都是浏览器可以识别的,对于浏览器能够识别的文件,会直接打开。对于路径错误或者不能识别的,例如excel,下载是没有问题。
网上找了好多方法,大都针对image图片的下载,试了几把,优化了一把,也挺好用:
/* 图片的下载 type:类型,即后缀名 name:下载的文件名称 url:url */ function downloadPicture(type, name, url) { var image = new Image() // 解决跨域 Canvas 污染问题 image.setAttribute('crossOrigin', 'anonymous'); image.src = url; image.onload = function () { // 创建一个canvas标签 var canvas = document.createElement('canvas') // 设置canvas的宽高 canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; var context = canvas.getContext('2d') context.drawImage(image, 0, 0); // 把canvas的内容转化为base64格式 var imageType = type === "png" ? "image/png" : "image/jpeg"; var base64url = canvas.toDataURL(imageType) // 生成一个a元素 var a = document.createElement('a'); a.download = name || '文件下载' a.href = base64url // 创建一个单击事件 var event = new MouseEvent('click'); // 触发a的单击事件 a.dispatchEvent(event) } }
但是这个方法,仅仅适用于图片,对于pdf或其他文件是不行的。
之前做过后端返回文件流,前端下载的例子,无论什么文件,都没问题,那么遵循这个思路,想办法把url转成文件流不就可以了吗?
于是乎,想到我们可以使用一个原生请求,设置responseType = 'blob' 这样的话,就可以通过请求文件的url,得到文件流。
function getFileAndDownload(fileName, url) { var x = new XMLHttpRequest(); x.open("GET", url, true); x.responseType = 'blob'; x.onload = function (e) { var blob = x.response; if ('msSaveOrOpenBlob' in navigator) {//IE导出 window.navigator.msSaveOrOpenBlob(blob, fileName); } else { var a = document.createElement('a'); a.download = fileName; a.href = URL.createObjectURL(blob); $("body").append(a); a.click(); $(a).remove(); } }; x.send(); }
完美解决,适用任何类型的文件。
注意一点是:请求的这个url要允许跨域或者在同域名下,否则也会失败。