前端下载普通文件与二进制流文件

前端下载文件一般会遇到这样两种状况html

  1. 文件上传到资源服务器上,后端只保存了文件地址,前端拿到后端返回的文件地址直接下载。
  2. 文件就存在后端服务器上(一般是临时根据前端参数动态生成,用完就删除),后端读取文件后向前端返回文件的二进制流。

下面如下载excel文件为例,分别模拟展现这两种状况。(前置准备:vscode,node8+,vue-cli3.5+)。前端

1、 经过文件地址直接下载vue

在空目录test下新建service目录模拟后端,新建index.html文件模拟前端。node

在service目录中新建一个excel文件 test.xlsx用于下载。ios

安装serve用来启动静态资源服务器ajax

npm install -g serve
复制代码

进入service目录,启动服务vue-cli

cd service 
serve -s
复制代码

此时这个test文件的地址就是:http://localhost:5000/test.xlsxnpm

在页面中放一个a标签,href中写上文件的路径,并写上download属性。axios

<a href="http://localhost:5000/test.xlsx" download>点击下载</a>
复制代码

在浏览器中打开index.html,点击下载。后端

这种下载至关于一个get请求,浏览器直接访问该静态资源地址,download属性告诉浏览器这个a标签不是打开页面预览而是进行下载。

这与一般在实际项目中经过ajax请求接口无关,只须要照常请求,由于后端返回的只是文件的地址,拿到地址后绑定在a标签中或者经过window.open()均可以进行下载,再也不单独在项目中进行演示。

2、二进制流文件下载

这种状况通常就是实际项目使用的ajax请求接口方式,好比post请求,前端传递若干参数,后端返回文件二进制流。

删除index.html,返回test目录下,使用vue-cli建立一个vue项目。

cd ../
vue create demo 
复制代码

选择最简单的default模板,建立好后进入项目目录安装axios,最后启动。

cd demo
npm i axios --save
npm run serve
复制代码

删除src/App.vue中的多余内容,添加一个下载按钮。

<input type="button" value="点击下载">
复制代码

在service目录中建立service.js写一个下载的接口。

关于跨域cors设置参考:juejin.cn/post/684490…

const http = require("http");
const fs = require("fs");

// 建立服务
const server = http.createServer((req,res) => {  
  // 下载接口  
  if(req.url === "/download") {    
    res.writeHead(200, {      
      "Content-type": "application/vnd.ms-excel", // 返回excel文件            
      // 跨域设置      
      "Access-Control-Allow-Origin": "*",      
      "Access-Control-Allow-Headers": "content-type"    
    })

    // 异步读取文件内容    
    fs.readFile("test.xlsx", (err, data) => {       
      // 返回二进制流文件        
      res.end(data)    
    })  
  }
})

// 服务启动在3000端口
server.listen(3000)
console.log("server run at 3000")
复制代码

在service目录下新开一个终端窗口,启动后端服务。

node service.js
复制代码

回到App.vue,给下载按钮添加点击事件。

<input type="button" value="点击下载" @click="handleDownload">

handleDownload() {  
  axios({    
    method: 'post',    
    url: "http://localhost:3000/download",    
    data: {      
      test: "test data"    
    } 
  }).then(response => {      
      console.log(response.data)  
   })
},
复制代码

此时点击下载,能够看到返回的结果是乱码。

其实根本原理跟上面普通下载同样,都是经过一个文件的地址去下载,因此如今关键就是如今把这些二进制数据生成一个文件url。

首先设置axios配置项返回结果为二进制格式。

axios({  
  method: 'post',  
  url: "http://localhost:3000/download",  
  data: {    
    test: "test data"  
  },  
  responseType: "arraybuffer" // arraybuffer是js中提供处理二进制的接口
})
复制代码

拿到返回数据后,将二进制数据生成一个文件url,用URL.createObjectURL生成url时须要传入Blob类型的参数。

关于Blob类型:juejin.cn/post/684490…

生成了url后就是模拟a标签来下载。

.then(response => {          
  // 用返回二进制数据建立一个Blob实例          
  let blob = new Blob([response.data], {            
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 
  }) // for .xlsx files          

  // 经过URL.createObjectURL生成文件路径          
  let url = window.URL.createObjectURL(blob)          

  // 建立a标签          
  let ele = document.createElement("a")          
  ele.style.display = 'none'          

  // 设置href属性为文件路径,download属性能够设置文件名称          
  ele.href = url          
  ele.download = "测试文件"          

  // 将a标签添加到页面并模拟点击          
  document.querySelectorAll("body")[0].appendChild(ele)          
  ele.click()          

  // 移除a标签          
  ele.remove()        
});
复制代码

回到浏览器点击下载,此次二进制流文件下载成功。

相关文章
相关标签/搜索