前端涉及的文件下载还有很多应用场景,那么前端文件下载有多少种方式呢?每种方法的优点和缺点是什么?让我们一一介绍。a标签通过a标签的download属性实现文件下载。这种方法是最简单也是最常用的方法。先看示例代码:下载上面的例子,我们点击下载,发现跳转到百度首页,实际上并没有下载文件。因为a标签下载只能下载同源文件,如果是跨域文件,包括图片、音频、视频等媒体文件,都是预览,不能下载。上面的代码直接通过写一个tag实现文件下载,我们也可以通过js实现,代码如下:consta=document.createElement('a')a.href='http://www.baidu.com'a.download='baidu.html'a.click()的效果和上面一样,都是跳转到百度首页,不下载文件。这里的重点是a标签的download属性,它是HTML5新增的。它的作用是指定下载的文件名。如果不指定,则根据请求内容的Content-Disposition确定下载的文件名。如果没有Content-Disposition,请求的URL的最后部分将用作文件名。.window.open上面使用标签的情况也可以通过window.open来实现,效果是一样的,代码如下:window.open('http://www.baidu.com','_blank')其中_blank是指定打开方式。如果不指定,它将在当前页面打开。如果此处指定了_blank,则会在新页面打开。同样,也可以使用a标签的download属性,代码如下:window.open('http://www.baidu.com','_blank','download=baidu.html')当然,这个方法也有缺陷,相对于a标签,这个方法不能下载.html,.htm,.xml,.xhtml等文件,因为这些文件会被当成html文件,所以会直接在当前页面。同样,跨域的文件也不能下载,毕竟是window.open,不是window.download(window.download是假设的)。location.href这个方法和window.open(url)一样,代码如下:location.href='http://www.baidu.com'这个方法有window.open的所有缺陷,所以不推荐使用,这里只是为了理解,就不做过多解释了。location.?其他属性这里的其他属性是指可以跳转到页面的属性,比如location.assign、location.replace、location.reload等,这些属性可以实现文件下载。代码如下:location.assign('http://www.baidu.com')location.replace('http://www.baidu.com')location.reload('http://www.baidu.com')location.reload这里有点特殊。它的作用是重新加载当前页面,但是它也可以接受一个参数,就是要重定向的页面,所以它也可以实现文件下载。当然,和location.href一样,这些方法都有同样的缺点,同时,每个属性都有自己的特点。这里只是为了扩展知识,不做过多解释。这种XMLHttpRequest的方式就是我们常说的ajax下载,包括axios、fetch等都是一样的,代码如下:constxhr=newXMLHttpRequest()xhr.open('GET','http://www.baidu.com')xhr.send()xhr.onload=function(){constblob=newBlob([xhr.response],{type:'text/html'})consta=document.createElement('a')A。href=URL.createObjectURL(blob)a.download='baidu.html'a.click()}这里不讲XMLHttpRequest相关的知识,只讲文件下载相关的部分。这里的主要逻辑是当我们的请求成功后,我们会得到responsebody的response,也就是我们要下载的内容,然后我们把它转化成一个blob对象,然后通过URL.createObjectURL创建一个url,然后通过a标签的download属性实现文件下载。这里有两个知识点,一个是blob对象,一个是URL.createObjectURL。5.1blob以下是blob对象的定义,来自MDN[1]:Blob对象表示一个不可变的、原始数据文件类对象。它的数据可以以文本或二进制格式读取,也可以转换为ReadableStream进行数据操作。Blob不一定代表JavaScript原生格式的数据。File接口基于Blob,继承了blob的功能并对其进行了扩展以支持用户系统上的文件。blob对象是html5中的一个新对象。用于存储二进制数据,如图片、视频、音频等。其用法如下:/**@param{Array}数组二进制数据@param{Object}options配置项@param{String}options。type文件类型,表示将放入blob的数组内容的MIME类型。@param{String}options.endings用于指定包含行结束符\n的字符串如何写。默认是透明的,即不会修改行结束符。也可以指定为native,也就是说\n会被转换为\r\n。*/constblob=newBlob([],{type:''})这里主要关注的是类型属性。默认情况下,blob对象是没有type属性的,所以这个Blob是一个无类型的Blob,文件不会被破坏,但是不能被正常识别。5.2URL.createObjectURL以下内容来自MDN[2]:URL.createObjectURL()静态方法创建一个包含表示参数中给定对象的URL的DOMString。此URL的生命周期与创建它的窗口中的文档相关联。这个新的URL对象代表指定的File对象或Blob对象。此方法用于创建url。它的作用是将一个blob对象转换成一个url。此url可用于下载文件或预览文件。代码如下:consturl=URL.createObjectURL(blob)这里需要注意的是,这个url的生命周期是和创建它的窗口中的文档绑定的,也就是说,当我们的文档销毁时,这个url会失效,所以我们需要适时销毁它,代码如下:URL.revokeObjectURL(url)回到刚才下载的问题,我们是通过blob对象解决的,但是我们的type属性是硬编码的。如果文件类型确定了,没有问题,但是如果这个接口是下载文件的接口,文件可能是各种类型的,我们应该怎么处理呢?这里没有正确答案。第一个可以和接口提供商协商。谈判计划不确定。二是通过response的header获取文件的类型,也就是我们要说的:consttype=response.headers['content-type']constblob=newBlob([response.data],{type})这里我们通过response的header获取type,然后创建一个blob对象,这样就可以正确下载文件了。其实content-type也可能是application/octet-stream。这时候我们就需要通过file-type获取文件的类型。以下代码通过file-type获取文件的类型:import{fileTypeFromStream}from'file-type';consttype=awaitfileTypeFromStream(response.body);constblob=newBlob([response.data],{type})file-type的使用可以参考[3]。综上所述,上面这么多解决方案,但其实最后还是落在了a标签上,所以无论是通过浏览器自带的行为下载还是通过ajax下载,最终的文件下载都是浏览器的行为。参考文献[1]MDN:https://developer.mozilla.org...[2]MDN:https://developer.mozilla.org...[3]此处:https://github.com/sindresorh。..
