前端文件下载,a标签下载,ajax下载亲测有效

本文介绍两种前端实现文件下载的方法:使用a标签download属性和通过ajax请求实现。文章详细解析了a标签download属性适用条件及限制,并提供了使用ajax、fetch及axios进行文件下载的具体示例。
摘要由CSDN通过智能技术生成

这段时间项目需要下载文件,刚开始直接用a标签的href加后端地址的方式就可以下载,这类方法可以下载zip文件等浏览器不能识别的文件,但是遇到下载txt和图片等文件就莫得办法了,因为浏览器会自动打开。

然后就去网上搜了一下,发现有很多人都说直接在a标签里加一个download属性就好了,并且这个可以设置文件名,但是很多都没有接受什么时候加这个属性会生效,所以用我亲自踩完坑的经历来解释一下,先看一个列子,比如:

<a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" download="text.png" target="_blank">点击下载</a>

各位可以运行上面这段代码试一试,地址是有效的

但是,很灵性的但是哈。(各位,重点来了,一定要仔细看)

但是这种方法根本不管用!浏览器还是直接打开图片了,原因是a标签加这个属性得分情况,必须要在同源(同域名、同协议、同端口号)时,才会生效,什么概念呢?

比如说前端项目布在http://192.168.88:8888 这个服务器上面,后端项目也布在同一个服务器同一个端口号下面,这种情况才可以下载,否则的话都不行。

并且就算是以上这种情况前端在本地调试的时候也是不会下载的,原因是在本地调试的时候前端地址一般都是http://localhost:300,很明显和后端地址不是同源嘛。

虽然做了反向代理,但还是不会下载的,不过推到线上就生效了。所以各位在用a标签下载的时候需要注意是否同源(主要看发布后是否同源)

既然说了ajax的方法肯定就还没完嘛,接下来讲一下第二种

先上代码:

//ajax方法
        const xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', true);
        xhr.responseType = 'blob';
        xhr.onload = function () {
            if (this.status === 200) {
                const fileName = 'test.png';
                const blob = new Blob([this.response]);
                const blobUrl = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = blobUrl;
                a.download = fileName;
                a.click();
                window.URL.revokeObjectURL(blobUrl);
            }
        };
        xhr.send();

// 用fetch发送请求
        fetch('https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png').then((res) => {
            res.blob().then((blob) => {
                const blobUrl = window.URL.createObjectURL(blob);
                console.log(blob);
                console.log(blobUrl);
                // 这里的文件名根据实际情况从响应头或者url里获取
                const filename = 'user.jpg';
                const a = document.createElement('a');
                a.href = blobUrl;
                a.download = filename;;
                a.click();
                window.URL.revokeObjectURL(blobUrl);
            });
        });

// axios下载
import axios from "axios";
import { message } from 'antd'

export const downloadFile = (method, url, config) => {
  let _data = null
  let _params = null
  if (method === 'GET' || method === 'get') {
    _params = config.params
  } else {
    _data = config.data
  }

  axios({
    url,
    method,
    params: _params,
    data: _data,
    responseType: 'blob',
    headers: {
      'Csrf-Token': '123',
    },

  }).then(res => {
    console.log(res)
    const str = res.headers['content-disposition']
    if (!res || !str) {
      message.error(res.message || '下载失败!')
      return
    }
    if (res && res.status === 200 && res.data) {
      const { data, headers, config } = res
      let fileName
      if (headers['content-disposition']) {
        fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
      } else if (data.fileName) {
        fileName = data.fileName
      } else {
        fileName = config.params?.fileName
      }
      // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
      const blob = new Blob([data], { type: headers['content-type'] })
      const dom = document.createElement('a')
      const downUrl = window.URL.createObjectURL(blob)
      dom.href = downUrl
      dom.download = decodeURIComponent(fileName)
      dom.style.display = 'none'
      document.body.appendChild(dom)
      dom.click()
      dom.parentNode.removeChild(dom)
      window.URL.revokeObjectURL(url)
    } else {
      message.error(res.message || '下载失败!')
    }
  }).catch(err => {
    message.error(err || '下载失败!')
  })
}

上面的代码也是可以运行的,地址有效

买一送一再来了一个fetch的

这种方法就不管同源不同源都会下载了,但是这毕竟是ajax请求了嘛,所以会涉及到跨域的问题,需要解决一下跨域问题,不过现在都会配置反选代理,所以也不是上面问题了,但是会有些小细节(如果不细节效果也出不来)

下面看实际项目中的用法

正常来说在项目中请求数据时地址都会写成/aip/xxx/xxx的对吧,所以这个地方一般会写成fetch("/api/xxx/xxx.txt"),对吧,看似很合理,但这样写了点击下载没有反应,也不报错,network也请求成功,但就是不会下载,为什么呢?我也不知道,哪个大佬要是知道一定评论解释一下。

但是我有个解决方案,只要把api换成后端地址就ok了,写成这样:fetch("/http://192.168.88:8888/xxx/xxx.txt"),前面那个"/"必须留着,否则就包跨域的错了,或者也可以写成fetch("http:localhost:3000/http://192.168.88:8888/xxx/xxx.txt")也可以,但是这种前面会被写死,等上线的时候还得改成线上的地址,所以推荐第一种,第一种会自动补全前面的地址,请求完的结果是:

 接下来看项目实际代码:

 

下载结果:

 这一看就知道是react加antd的项目了

好了,具体两种用法就是这样了,都是自己亲测有效的,大家根据自己情况选择。其实还有其他的方式,一是我懒了没去研究,二是我觉得有这两种就够用了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值