前言
最近在做一个系统,中间涉及到报表导出的功能,所以我思考了一下我曾经经理过的文件导出的实现方案。
使用get请求后端直接拿文件
通过使用get请求后端拿文件的这个方法简单粗暴,解决问题,同时能够避免别的一些问题。具体的实现流程如下:
<a href="文件的地址" download="文件名称" target="_blank">下载文件</a>
<button id="btn_download">下载</button>
var btn = document.getElementById('btn_download')
btn.addEventListener('click', function() {
window.open('文件下载地址')
})
以上的文件下载的方法相对来说比较粗暴简单貌似对于前端来说没有什么太大影响。
通过使用ajax请求后端接口获取一个文件地址然后进行下载
如果说上面的方法可行的话,ajax请求后端生成一个文件然后将文件的地址转发给前端,然后再进行下载,这样的好处就是生成文件的服务器以及文件和服务不在同一台机器上的时候会用到,还有一种情况,其实就是我们想要下载的资源在云存储中,但是对于我们的业务来说,存在数据库中的内容仅仅只是一个文件的路径或者是文件的一个code,然后通过转换成一个下载路径进行下载的(比如说使用7牛云的时候会存一个key,然后会根据这个key生成一个链接来进行下载)。
好针对于这个方法的具体的实现如下:
$.ajax({
url: '接口地址',
data: {'请求的数据'},
type: 'post',
dataType: 'json',
success: function(res) {
// 成功
if (res.code === 0) {
// res.url就是后端生成的我们想要下载文件的路径地址
window.open(red.url)
}
}
})
上面呢是一个基础的实现方法。针对于上面的下载方法,其实是有一个坑的,而且这个坑还很深。就是我们在ajax请求回来之后自动打开页面会被浏览器给拦截(主要是因为浏览的安全机制引起的。防止恶意请求),这样,如果仅仅是自己使用的话,我们可以通过设置自己的浏览器允许那就行,但是一般几乎所有的情况并不是我们一个人在使用,我们不可能让其他人都去设置自己的浏览器的。因此这个方法我们必须要做成通用的一个方法。
但是会有人有疑问,同样是打开窗口为什么我们通过单击按钮能进行打开,但是通过ajax不会进行打开呢,主要是因为我们单击按钮,是一个连续的连续执行的方法进行的打开,但是通过ajax则是一个异步的方法。针对于上面的这个原因,我们可以将我们的异步方法转换成同步的方法来进行请求,并下载文件:
$.ajax({
url: '接口地址',
data: {'请求的数据'},
type: 'post',
dataType: 'json',
async: false,
success: function(res) {
// 成功
if (res.code === 0) {
// res.url就是后端生成的我们想要下载文件的路径地址
window.open(red.url)
}
}
})
经过上面的改造,我们成功下载得到了我们的文件。
其实还有第三种方法
对于第三种方法,就是我们通过使用ajax进行post请求,获取后端的文件的blob,然后在前端进行转换成文件链接的形式,再进行下载:
function creatJumpFile(url, title, cal, conText) {
const a = document.createElement('a')
a.download = title
a.href = url
setTimeout(function() {
a.click()
a.remove()
})
}
function downloadFile(url, data, title) {
return new Promise((reslove, reject) => {
if (type === 'post') {
request({
url,
method: 'post',
data,
responseType: 'blob'
}).then(({ data }) => {
console.log(data)
const blobUrl = window.URL.createObjectURL(data)
title = title || data.name || 'download'
creatJumpFile(blobUrl, title)
resolve(conText)
}, err => {
reject(err)
})
})
}
这个方法中有一个转换文件的方法,这个方法一定要注意好后端设置的blob的type跟实际的类型保持一致,否则会出问题。就比如说我遇到的就是后端明明想要下载的文件格式为xlsx,但是设置成了xls的格式的类型,这就导致转换成文件的时候出了问题。接下来附上一个下载的文件的类型,和blob 的type的一个表:
Ext | MIME Type |
---|---|
.doc | application/msword |
.dot | application/msword |
.docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
.dotx | application/vnd.openxmlformats-officedocument.wordprocessingml.template |
.docm | application/vnd.ms-word.document.macroEnabled.12 |
.dotm | application/vnd.ms-word.template.macroEnabled.12 |
.xls | application/vnd.ms-excel |
.xlt | application/vnd.ms-excel |
.xla | application/vnd.ms-excel |
.xlsx | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
.xltx | application/vnd.openxmlformats-officedocument.spreadsheetml.template |
.xlsm | application/vnd.ms-excel.sheet.macroEnabled.12 |
.xltm | application/vnd.ms-excel.template.macroEnabled.12 |
.xlam | application/vnd.ms-excel.addin.macroEnabled.12 |
.xlsb | application/vnd.ms-excel.sheet.binary.macroEnabled.12 |
.ppt | application/vnd.ms-powerpoint |
.pot | application/vnd.ms-powerpoint |
.pps | application/vnd.ms-powerpoint |
.ppa | application/vnd.ms-powerpoint |
.pptx | application/vnd.openxmlformats-officedocument.presentationml.presentation |
.potx | application/vnd.openxmlformats-officedocument.presentationml.template |
.ppsx | application/vnd.openxmlformats-officedocument.presentationml.slideshow |
.ppam | application/vnd.ms-powerpoint.addin.macroEnabled.12 |
.pptm | application/vnd.ms-powerpoint.presentation.macroEnabled.12 |
.potm | application/vnd.ms-powerpoint.presentation.macroEnabled.12 |
.ppsm | application/vnd.ms-powerpoint.slideshow.macroEnabled.12 |