如何用JS下载文件
https://scarletsky.github.io/2016/07/03/download-file-using-javascript/

下载总结:

  • 不要用 JavaScript 下载文件,限制多多,又不好用,
  • 直接用 html的 a标签下载就好

a标签实现下载

只要一个 a 标签,就可以实现文件下载
纯前端技术实现文件下载,直接把a标签的href属性设置为文件路径即可
但是,对于 txt , jpg , pdf 等浏览器支持直接打开的文件不会被执行下载,

  • 而是会直接打开,这时候一个新属性就要上场了—【download】
  • 如果不想借助后台而要实现文件下载,给a标签加download绝对是首选之策
  • download属性不止可以实现下载,其属性值还可以规定下载时的文件名,如果不填写,会自动使用默认文件名
  • IE 和 Safari 不会直接下载,但是会有下载提示框弹出,只是多绕了一步

    1. <a href="https://host/user.xlxs" download="user.xlsx">下载文件</a>
  • href: 下载地址

  • download: 文件名

通过js判断浏览器的兼容性去选择性给用户一些提示信息

  1. var supportDownload = "download" in document.createElement("a");
  2. if(!supportDownload){
  3. // code
  4. }

image.png
【注意】:

  • html5中 a标签的 download属性虽然可以指定下载的文件名,
  • 但是这个属性在第三方地址跨域下载以及和通过后台接口下载东西的时候就会失效,就改不了名字

button按钮下载

本质上还是用 js动态创建一个 a标签,然后给 a标签添加 href,download属性

  1. <button onclick="dealDownLoad('https://host/user.docx')">下载</button>
  2. function dealDownLoad(url){
  3. const a = document.createElement("a");
  4. a.href = url;
  5. a.download = "user.docx"
  6. a.click();
  7. }
  1. 用 JavaScript 创建一个隐藏的 标签
  2. 设置它的 href 属性
  3. 设置它的 download 属性
  4. 用 JavaScript 来触发这个它的 click 事件

post下载

https://segmentfault.com/a/1190000017392696
https://www.cxybb.com/article/heixiuheixiu666/105288231

  1. export function downloadFile(blob, filename = 'monitor.json') {
  2. const downloadUrl = URL.createObjectURL(blob);
  3. const a = document.createElement('a');
  4. a.style.display = 'none';
  5. a.download = filename;
  6. a.href = downloadUrl;
  7. document.body.appendChild(a);
  8. a.click();
  9. document.body.removeChild(a);
  10. URL.revokeObjectURL(downloadUrl);
  11. }

XMLHttpRequest下载

header中带上用于鉴权的token

  1. <a href="#" onClick={onDownload}>下载</a>
  2. function onDownload(event) {
  3. // 使 a自带的方法失效,即无法调整到href中的URL
  4. event.preventDefault();
  5. const url = 'http://localhost:8000/file/export/files'; // 请求的URl接口
  6. const xhr = new XMLHttpRequest(); //定义http请求对象
  7. xhr.open("post", url, true);
  8. xhr.responseType = "blob"; // 返回类型blob
  9. xhr.setRequestHeader("accessToken", "此处获取token");
  10. xhr.setRequestHeader("Content-type", "application/application/octet-stream");
  11. // 请求完成的处理函数,请求前可以增加加载框/禁用下载按钮逻辑
  12. xhr.onload = function () {
  13. if (this.status === 200) {
  14. const blob = this.response;
  15. const reader = new FileReader();
  16. reader.readAsDataURL(blob); // 转换为base64,可以直接放入a标签href
  17. reader.onload = function (e) {
  18. console.log(e); // 有没有接收到数据流
  19. // 转换完成,创建一个a标签用于下载
  20. const a = document.createElement('a');
  21. a.download = '用户列表.xlsx'; //此处填写文件地址
  22. a.href = e.target.result;
  23. document.body.appendChild(a);
  24. a.click();
  25. document.body.removeChild(a);
  26. }
  27. }
  28. else {
  29. alert("出现了未知的错误!");
  30. }
  31. }
  32. xhr.send();
  33. };

fetch下载

fetch下载其实就是,使用 fetch 去模拟 a 标签的下载过程

  1. fetch('https://host/user.docx')
  2. .then(res => res.blob())
  3. .then(blob => {
  4. const a = document.createElement('a');
  5. const url = window.URL.createObjectURL(blob);
  6. const filename = 'myfile.docx';
  7. a.href = url;
  8. a.download = filename;
  9. a.click();
  10. window.URL.revokeObjectURL(url);
  11. });
  1. fetch 一个接口获取其内容并转成 blob 对象。
  2. 将 blob 对象使用 createObjectURL 方法转化成 ObjectURL,等同于一个下载地址链接。
  3. 创建一个 a 标签,并赋予 ObjectURL 且执行一次 click
  4. 通过 revokeObjectURL 回收 ObjectURL

createObjectUrl

window.URL.revokeObjectURL

  • 只能获取 [Blob] 或 [File] 对象
  • 释放一个通过URL.createObjectURL()创建的对象URL,不会立即释放内存;无法强制从内存中删除

createObjectURLMDN文档 https://developer.mozilla.org/zh-CN/docs/Web/API/URL/createObjectURL
revokeObjectURL https://developer.mozilla.org/zh-CN/docs/Web/API/URL/revokeObjectURL

URL.createObjectURL(),根据传入的参数创建一个指向该参数对象的URL

  • 这个URL的生命仅存在于它被创建的这个文档里. 新的对象URL指向执行的File对象或者是Blob对象.
  1. objectURL = URL.createObjectURL(blob || file);
  2. // 销毁文件路径
  3. window.URL.revokeObjectURL(objectURL);

当图片加载完成后释放对象URL
https://www.cnblogs.com/liulangmao/p/4262565.html

axios下载

  1. function App() {
  2. function createFile(res) {
  3. const a = document.createElement('a');
  4. const blob = new Blob([res.data],{type: 'application/vnd.ms-excel'});
  5. // 获取heads中的filename文件名
  6. const disposition = res.headers["content-disposition"]
  7. let temp = disposition.split(";")[1].split("filename=")[1];
  8. const fileName = decodeURIComponent(temp);
  9. console.log(fileName);
  10. a.style.display = 'none'
  11. a.href = URL.createObjectURL(blob);
  12. a.setAttribute('download', fileName);
  13. document.body.appendChild(a);
  14. a.click();
  15. document.body.removeChild(a);
  16. }
  17. function onDownload() {
  18. axios({
  19. method: 'post',
  20. url: "http://localhost:8000/file/export/files",
  21. responseType: 'blob'
  22. })
  23. .then(res => createFile(res))
  24. .catch(error => {
  25. console.log(error)
  26. })
  27. }
  28. // 如果是 a标签,需要阻止默认事件
  29. // event.preventDefault();
  30. return (
  31. <Button onClick={onDownload}>下载</Button>
  32. )
  33. }

axios下载大文件报错

当文件过大时,点击下载提示:文件下载失败-网络错误,原因:

  • 截取尺寸较大 导致生成base64长度太大,达到a标签的href上限
  • 解决方案: 将base64 dataURL转换为Blob文件对象 ```jsx // 将 a.href = e.target.result; 改成
    a.href = URL.createObjectURL(dataURLToBlob(e.target.result)); // 如果是谷歌浏览器的话为 a.href = webkitURL.createObjectURL(dataURLToBlob(e.target.result));

function dataURLToBlob(dataurl) { const arr = dataurl.split(‘,’); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]) const n = bstr.length const u8arr = new Uint8Array(n);

while(n—){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); }

  1. <a name="JSUmE"></a>
  2. ### 下载权限校验
  3. 权限校验了,如检查该用户是否有下载的权限,是否有高速下载的权限等等。<br />这时候,我们可以利用 JavaScript 做一些预处理
  4. ```jsx
  5. fetch('http://somehost/check-permission', options).then(res => {
  6. if (res.code === 0) {
  7. var a = document.createElement('a');
  8. var url = res.data.url;
  9. var filename = 'myfile.zip';
  10. a.href = url;
  11. a.download = filename;
  12. a.click();
  13. } else {
  14. alert('You have no permission to download the file!');
  15. }
  16. });

通过后端服务器来计算出用户的下载链接,
然后再利用之前提到的动态创建 标签的方式来实现下载

动态文件下载

有时候需要做导出数据的功能,例如:把数据库中的某些数据导出到 Excel 中,然后再返回客户端。

  • 这时候我们就不能简单的指定 href 属性,因为对应的 URL 并不存在
  • 只能通过 JavaScript 对服务器发出一个请求,通知它去生成某个文件,然后把对应的 URL 返回给客户端
  • 这个过程和上面「权限校验」很像?因为我们只是对 URL 做了一些预处理而已

response 文件下载响应头

下载 zip压缩文件

  1. header('Content-Type: application/octet-stream');
  2. header('Content-Disposition: attachment; filename="ITblog.zip"');
  3. header('Content-Transfer-Encoding: binary');
  4. readfile('test.zip');

下载 xls文件

  1. header('Content-Disposition: attachment; filename=ithhc.xlsx');
  2. 服务端设置 header
  3. setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
  4. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  5. header('Content-Length: '.filesize('./test.xls'));
  6. header('Content-Transfer-Encoding: binary');
  7. header('Cache-Control: must-revalidate');
  8. header('Pragma: public');
  9. readfile('./test.xls');