a标签下载
<body>
<button onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">a标签下载</button>
<script>
function downloadEvt(url, fileName = '未知文件') {
const el = document.createElement('a');
el.style.display = 'none';
el.setAttribute('target', '_blank');
/**
* download的属性是HTML5新增的属性
* href属性的地址必须是非跨域的地址,如果引用的是第三方的网站或者说是前后端分离的项目(调用后台的接口),这时download就会不起作用。
* 此时,如果是下载浏览器无法解析的文件,例如.exe,.xlsx..那么浏览器会自动下载,但是如果使用浏览器可以解析的文件,比如.txt,.png,.pdf....浏览器就会采取预览模式
* 所以,对于.txt,.png,.pdf等的预览功能我们就可以直接不设置download属性(前提是后端响应头的Content-Type: application/octet-stream,如果为application/pdf浏览器则会判断文件为 pdf ,自动执行预览的策略)
*/
fileName && el.setAttribute('download', fileName);
el.href = url;
console.log(el);
document.body.appendChild(el);
el.click();
document.body.removeChild(el);
}
</script>
</body>
优点:
- 可以下载txt、png、pdf等类型文件
- download的属性是HTML5新增的属性href属性的地址必须是非跨域的地址,如果引用的是第三方的网站或者是前后端分离项目(调用后台的接口),这时dowmload就会不起作用。此时,如果
缺点:
- a标签只能做get请求,所有url有长度限制
- 无法获取下载进度
- 无法在header中携带token做鉴权操作
- 跨域限制
- 无法判断接口是否返回成功
- IE兼容问题
form标签下载
<body>
<button onclick="inputDownloadEvt('get', 'http://192.168.66.183:13666/download', 'name', 'HAP.pdf')">form标签下载</button>
<script>
/**
* @param {String} method - 请求方法get/post
* @param {String} url
* @param {String} paramsKey - 请求参数名
* @param {String} paramsValue - 请求参数值
*/
function inputDownloadEvt(method, url, paramsKey, paramsValue) {
const form = document.createElement('form');
form.style.display = 'none';
form.setAttribute('target', '_blank');
form.setAttribute('method', method);
form.setAttribute('action', url);
const input = document.createElement('input');
input.setAttribute('type','hidden');
// 对于get请求 最终会拼成http://192.168.66.183:13666/download?name=HAP.pdf
input.setAttribute('name', paramsKey);
input.setAttribute('value', paramsValue);
form.appendChild(input);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
</script>
</body>
优点:
- 兼容性好,不会出现URL长度限制
- get和post都可以
缺点:
- 无法获取下载进度
- 无法在header中携带token做鉴权操作
- 无法直接下载浏览器可直接预览的文件类型(txt、png、pdf会直接预览)
- 无法判断接口是否返回成功
window.open 下载
<body>
<button
onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">
window.open下载
</button>
<script>
function downloadEvt(url) {
window.open(url, '_self');
}
</script>
</body>
优点:
- 简单方便直接
缺点:
- 会出现URL长度限制问题
- 需要注意url编码问题
- 无法获取下载进度
- 无法在header中携带token做鉴权操作
- 无法直接下载浏览器可直接预览的文件类型(txt、png、pdf会直接预览)
- 无法判断接口是否返回成功
iframe下载
<body>
<button
onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">
iframe下载
</button>
<script>
// 批量下载时,动态创建a标签,会始终只下载一个文件,改为动态创建iframe标签
function downloadEvt(url) {
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe);
setTimeout(() => {
document.body.removeChild(iframe);
}, 200);
}
</script>
</body>
优点:
- 可以下载txt、png、pdf等类型文件
缺点:
- 无法获取下载进度
- 无法在header中携带token做鉴权操作
- 无法判断接口是否返回成功
- 兼容、性能差
location.href 下载
<body>
<button
onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">
location.href下载
</button>
<script>
function downloadEvt(url) {
window.location.href = url;
}
</script>
</body>
优点:
- 简单方便直接
- 可以下载大文件(G以上)
缺点:
- 会出现URL长度限制问题
- 需要注意url编码问题
- 无法获取下载进度
- 无法在header中携带token做鉴权操作
- 无法直接下载浏览器可直接预览的文件类型(txt、png、pdf会直接预览)
- 无法判断接口是否返回成功
ajax下载(blob)
// blob导出文件
downloadFile: (blob, fileName) => {
try {
const link = document.createElement('a')
link.download = decodeURIComponent(fileName)
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(link.href)
document.body.removeChild(link)
} catch (err) {
this.disposeErrorResult(err)
}
},
// method:get/post url:路径 config:请求头配置 callback:下载方法(固定) params:post方法的请求参数
downloadFileDataOrError: (method,url,config,callback,params) => {
try {
let configs_params=null;
if(method=='post'){
configs_params={...params}
}else{
configs_params={...config}
}
axios[method](url,{...configs_params},{
...config,
}).then(function (response) {
const blob2 = response.data.text()
blob2.then((result)=>{
let JSON_RESULT=''
try {
JSON_RESULT = JSON.parse(result);
Modal.error({title:JSON_RESULT.errorMessage} );
} catch (error) {
const blob = new Blob([response.data]);
let content_disposition = response.headers['content-disposition']
let fileName = null;
if(content_disposition){
if(content_disposition.includes('filename*=')){
fileName = content_disposition.split(';')[1].split(`'`)[2]
}else{
fileName = content_disposition.split('filename=')[1]
if(['"',"'"].includes(fileName[0])&&['"',"'"].includes(fileName[fileName.length-1])){
fileName = fileName.substring(1,fileName.length-1)
}
}
}
callback(blob, fileName);
}
})
}).catch(function (error) {
// alert(error);
});
} catch (err) {
this.disposeErrorResult(err)
}
},
async exportData(url, config, callback) {
try {
const response = await axios(url, config)
const blob = new Blob([response.data])
let content_disposition = response.headers['content-disposition']
let fileName=null;
if(content_disposition){
if(content_disposition.includes('filename*=')){
fileName = content_disposition.split(';')[1].split(`'`)[2]
}else{
fileName = content_disposition.split('filename=')[1]
if(['"',"'"].includes(fileName[0])&&['"',"'"].includes(fileName[fileName.length-1])){
fileName=fileName.substring(1,fileName.length-1)
}
}
typeof callback == 'function' && callback(blob, fileName)
}
} catch (err) {
this.disposeErrorResult(err)
}
},
// fetch导文件数据
async exportDataFetch (url = "GET", config, callback = Util.downloadFile) {
try {
const response = await fetch(url, config)
if (response.status !== 200) {
this.disposeErrorResult(response)
}
const blob = await response.blob()
let content_disposition = response.headers.get('content-disposition')
let fileName = null;
if (content_disposition) {
if (content_disposition.includes('filename*=')) {
fileName = content_disposition.split(';')[1].split(`'`)[2]
} else {
fileName = content_disposition.split('filename=')[1]
if (['"', "'"].includes(fileName[0]) && ['"', "'"].includes(fileName[fileName.length - 1])) {
fileName = fileName.substring(1, fileName.length - 1)
}
}
typeof callback == 'function' && callback(blob, fileName)
}
} catch (err) {
this.disposeErrorResult(err)
}
},