很多时候,在我们开发的过程中,除了上传文件,还经常会遇到下载文件这一需求,其实也不太能算是需求,毕竟能上传肯定要能下载嘛。对于其他的浏览器不是很清楚,如果是chrome的话,用a标签是无法下载图片,txt...等,因为浏览器可以解析这几种格式,点了之后就不是下载,而是变成预览。
       对于这个问题,网上很多互相抄来抄去的文章,大致给出了以下这几种方法:


    • a标签添加download属性,此方法在chrome下一点用都没有,图片,文本还是照样是预览
    • 使用form发送action,此方法没有尝试,不过应该也有兼容性问题
    • 使用iframe来获取,不熟悉,使用了之后没用,可能使用方法不对
    • 发送 XMLHttpRequest,然后设置返回二进制文件,通过返回的创建一个临时 url 进行下载,此方法在本地开发可行,放上服务器后报错 Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided,大致意思就是这个方法不能这么使,但其实就是要这么使,网上文章给的解释都是一堆跟video的文件流有关的,一点用处都没有。其实不是这个方法有问题,而是你通过这种方式返回的blob在线上运行时有问题,具体输出看不到就没去深究,遇到这个问题,最简单的就是摒弃这个方法。
    • 使用插件downloadjs,不熟悉,而且也觉得没有必要,实现方式也是去发个请求改成二进制后下载下来,记得放弃它是因为看到一篇文章说这个插件不能支持中文路径,未使用,不知其是否可行。


      所以说,这几种方法局限性都很大,有的甚至就根本没有作用,经过自己设想了一下,开发过程中就一直使用axios来调接口,可不可以使用axios通过文件的url来下载文件呢,采用这个想法,试了一下,目前在chrome浏览器下表现正常,0 errors, 0 warnings,一样的道理,使用平常调取接口的方式,ajax应该也可以。这里注意可能会出现的跨域问题即可。具体使用如下:

    import axios from 'axios';
    //下载文件
    export function download(url) {
      return axios.get(url, {responseType: 'blob'});
    }
    

    <template>
      <div>
        <!--...-->
        <!--省略其他非必要代码-->
        <i
          class="el-icon-download"
          style="color:#409eff;"
          onclick="downloadDocs(file)"
        ></i>
        <!--...-->
      </div>
    </template>
    
    <script>
      import {config} from '@/config';
      import {download} from '@/api/download';
      export default {
        data() {
          return {
            host: config.host,
          };
        },
        //...省略非必要代码
        methods: {
          //...省略非必要代码
          downloadDocs(file) {
            if (file.uploading) {
              this.$message({
                message: '文件上传中,请稍后',
                type: 'warning',
              });
              return;
            }
    
            downloadDoc(this.host + file.url)
              .then(response => {
                if (response.status == 200) {
                  const content = response.data;
                  // 创建a标签并点击, 即触发下载
                  let url = window.URL.createObjectURL(new Blob([content]));
                  let link = document.createElement('a');
                  link.style.display = 'none';
                  link.href = url;
                  link.setAttribute('download', file.name);
                  // 模拟
                  document.body.appendChild(link);
                  link.click();
                  // 释放URL 对象
                  window.URL.revokeObjectURL(link.href);
                  document.body.removeChild(link);
                } else {
                  this.$message.error('获取文件失败!');
                }
              })
              .catch(err => {
                this.$message.error(err);
              });
          },
        },
        //...省略非必要代码
      };
    </script>
    

      通过此方法,目前已可以实现在chrome浏览器下点击后就把文件下下来,不会再把图片文本那些当成可以解析的格式从而变成预览。这个方法也就是在没有后端专门下载文件的接口下使用,如果是正常情况还是让后端放一个下载文件的接口可能会更好一点,至少不会暴露文件的url,而且可以在后端服务器上设置,使得文件更加不容易被不怀好意的人获取。此方法适用于想单纯通过前端去下载文件,同时记录下来也是为了更好的帮助遇到此问题的人儿们,当然,如果有更好的方法,欢迎大神们评论区留言,不吝赐教。