纯前端下载pdf链接文件,而不是打开预览的解决方案
纯前端下载pdf链接文件,而不是打开预览的解决方案
一,介绍与需求
1.1,介绍
XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
问题:Chrome 会自动调用内置的 pdf 阅读器打开
1.2,需求
在谷歌(Chrome)浏览器中,使用a标签属性download下载pdf链接文件,如果是相同域时,可以直接下载;但是如果域不同,则不是下载,而是直接打开页面预览文件。但是需求是直接点击下载文件,而不是打开预览;以及下载后台返回的文件流。
二,下载文件
已发布npm包:web-downloadfile,运行如下命令即可安装使用
cnpm install web-downloadfile --save
目前只提供三个Api,分别如下:
import { base64ToFileOrBlob, saveFileToBlob, saveFileToLink } from 'web-downloadfile';
详细的使用方式可查看官网web-downloadfile
2.1,思路
通过a标签的download属性,我们可以直接下载后台接口返回的数据流文件;故此,我们是否可以模拟发送http请求,将文件链接转换成文件流来使用a标签download下载。以下主要介绍链接文件转文件流下载的思路与方法
2.2,文件路径转文件流
1,先校验是否是路径链接
使用正则表达式校验url是否合法
let reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\/])+$/;
if (!reg.test(url)) {
throw new Error("传入参数不合法,不是标准的链接");
}
2,创建XMLHttpRequest对象
模拟发送http请求,获取文件流
let xhr = new XMLHttpRequest();//创建 XMLHttpRequest 对象
xhr.open('get', 'http://url', true);//规定请求的类型、URL 以及是否异步处理请求。三个参数分别是 method:请求的类型;GET 或 POST url:文件在服务器上的位置 async:true(异步)或 false(同步)
xhr.setRequestHeader('Content-Type', `application/pdf`);//设置请求头
xhr.responseType = "blob";//返回的数据类型 这儿需要blob对象
xhr.onload = function () {//请求成功回调函数
if (this.status == 200) {
//接受二进制文件流
var blob = this.response;
}
}
xhr.send();//将请求发送到服务器
3,完整方法
/**
* 文件链接转文件流下载--主要针对pdf 解决谷歌浏览器a标签下载pdf直接打开的问题
* @param url :文件链接
* @param fileName :文件名;
* @param type :文件类型;
*/
function fileLinkToStreamDownload(url, fileName, type) {
let reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\/])+$/;
if (!reg.test(url)) {
throw new Error("传入参数不合法,不是标准的文件链接");
} else {
let xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.setRequestHeader('Content-Type', `application/${type}`);
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status == 200) {
//接受二进制文件流
var blob = this.response;
downloadExportFile(blob, fileName, type)
}
}
xhr.send();
}
}
2.3,下载文件
1,创建下载链接
let downloadElement = document.createElement('a');
let href = blob;
if (typeof blob == 'string') {
downloadElement.target = '_blank';//如果是链接,打开新标签页下载
} else {
href = window.URL.createObjectURL(blob); //创建下载的链接
}
downloadElement.href = href;//下载链接
2,模拟点击下载链接
downloadElement.download = tagFileName + moment(new Date().getTime()).format('YYYYMMDDhhmmss') + '.' + fileType; //下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); //点击下载
3,下载完成后释放资源
document.body.removeChild(downloadElement); //下载完成移除元素
if (typeof blob != 'string') {
window.URL.revokeObjectURL(href); //释放掉blob对象
}
4,完成方法
/**
*下载导出文件
* @param blob :返回数据的blob对象或链接
* @param tagFileName :下载后文件名标记
* @param fileType :文件类 word(docx) excel(xlsx) ppt等
*/
function downloadExportFile(blob, tagFileName, fileType) {
let downloadElement = document.createElement('a');
let href = blob;
if (typeof blob == 'string') {
downloadElement.target = '_blank';
} else {
href = window.URL.createObjectURL(blob); //创建下载的链接
}
downloadElement.href = href;
downloadElement.download = tagFileName + moment(new Date().getTime()).format('YYYYMMDDhhmmss') + '.' + fileType; //下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); //点击下载
document.body.removeChild(downloadElement); //下载完成移除元素
if (typeof blob != 'string') {
window.URL.revokeObjectURL(href); //释放掉blob对象
} }
2.4,base64对象转文件对象
主要针对图片,不过其他文件也可
/**
* base64对象转文件对象
* @param urlData :数据的base64对象
* @param type :类型 image/png;
* @returns {Blob}:Blob文件对象
*/
function base64ToBlob(urlData, type) {
let arr = urlData.split(',');
let array = arr[0].match(/:(.*?);/)
let mime = (array && array.length > 1 ? array[1] : type) || type;
// 去掉url的头,并转化为byte
let bytes = window.atob(arr[1]);
// 处理异常,将ascii码小于0的转换为大于0
let ab = new ArrayBuffer(bytes.length);
// 生成视图(直接针对内存):8位无符号整数,长度1个字节
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], {
type: mime
});
}
2.5,使用实例
1,文件链接转文件流下载
fileLinkToStreamDownload('http://127.0.0.1/download.pdf', '下载文件实例', 'pdf')
2,base64对象转文件对象下载
let blob = base64ToBlob('data:image/png;base64,iVBORw0KGgo=...','image/png')//获取图片的文件流
downloadExportFile(blob, 'download', 'png')
问题记录:浏览器缓存问题
由于浏览器的缓存机制,当我们使用XMLHttpRequest发出请求的时候,浏览器会将请求的地址与缓存中的地址进行比较,如果存在相同记录则根据不向服务器发出请求而直接返回与上一次请求相同内容。
解决这类缓存问题的办法:
1,时间戳方法 —即在每次请求的url后面加上当前时间的字符串或其他类似的不会重复的随机字符串,这样浏览器每次发出的是不同的url,即会当做不同的请求来处理,而不会从缓存中读取。
if(url.indexOf("?")>=0){//判断url中是否已经带有参数
url = url + "&t=" + (new Date()).valueOf();
}else{
url = url + "?t=" + (new Date()).valueOf();
}
2,在XMLHttpRequest发送请求之前加上:
加If-Modified-Since头
xhr.setRequestHeader("If-Modified-Since","0");
xhr.send(null);
纯前端下载pdf链接文件,而不是打开预览的解决方案的更多相关文章
- 纯前端导出pdf文件
纯前端js导出pdf,已经用于生产环境. 工具: 1.html2canvas,一种让html转换为图片的工具. 2.pdfmake或者jspdf ,一种生成.编辑pdf,并且导出pdf的工具. pdf ...
- Android Studio xml文件中的布局预览视图
操作系统:Windows 10 x64 IDE:Android Studio 3.3.1 更新了Android Studio之后,xml文件中的布局预览视图变得如此简洁! 原因是没有勾选Show La ...
- JavaScrip 原生多文件上传及预览 兼容多浏览器
JavaScrip 原生多文件上传及预览 兼容多浏览器 html代码块 <div class="container"> <label>请选择一个图像文件:& ...
- form表单系列中文件上传及预览
文件上传及预览 Form提交 Ajax 上传文件 时机: 如果发送的[文件]:->iframe, jQurey(),伪Ajax 预览 import os img_path = os.path.j ...
- servlet实现文件上传,预览,下载和删除
一.准备工作 1.1 文件上传插件:uploadify: 1.2 文件上传所需jar包:commons-fileupload-1.3.1.jar和commons-io-2.2.jar 1.3 将数 ...
- 最好用的js前端框架、组件、文档在线预览插件
这里收集的都是个人认为比较好的js框架.组件 js前端ui框架 此处列举出个人认为最好的几个框架(排序即排名),现在好点的框架商用都需要付费,以下几个也不例外,但是由于组件丰富,都可以作为企业应用的完 ...
- 结合bootstrap fileinput插件和Bootstrap-table表格插件,实现文件上传、预览、提交的导入Excel数据操作流程
1.bootstrap-fileinpu的简单介绍 在前面的随笔,我介绍了Bootstrap-table表格插件的具体项目应用过程,本篇随笔介绍另外一个Bootstrap FieInput插件的使用, ...
- sublime3下载安装及常用插件、浏览器预览设置
之前与学习前端有关的软件都安装在了实验室电脑上,最近由于要放寒假(也许我寒假回去会学习呢),于是得在笔记本电脑上重新安装一遍.几个软件各种出错,花了一下午才安装好,必须记录下来啊! 这篇文章主要介绍s ...
- form里面文件上传并预览
其实form里面是不能嵌套form的,如果form里面有图片上传和其他input框,我们希望上传图片并预览图片,然后将其他input框填写完毕,再提交整个表单的话,有两种方式! 方式一:点击上传按钮的 ...
随机推荐
- springcloud-eureka客户端服务注册(含demo源码)
1. 场景描述 前几天介绍了下springcloud的Eureka注册中心(springcloud-注册中心快速构建),今天结合springboot-web介绍下eureka客户端服务注册. 2. 解 ...
- WEB前端--返回顶部特效源码
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...
- 20131201-插件-XML-第十二天(未完)
以后再写代码的时候,先从中间层|接口|协议开始入手. 在写XML时注意的事情: 在EditPlus中,Tab是缩进 在头文件中的编码格式是"utf-8"是,在Editplus中保存 ...
- Learning the Depths of Moving People by Watching Frozen
基于双目的传统算法 对静止的物体, 在不同的 viewpoints 同一时刻进行拍摄, 根据拍摄到的结果, 使用三角测量算法计算出平面 2D 图像在 3D 图像中的坐标 单目 Ground Truth ...
- /data/src/dragon/bidder_mod//src/proto_adapters/dragon_wax_adapter.h:11:对‘vtable for DragonWaxAdapter’未定义的引用
dragon/bidder_mod/config中增加: $ngx_addon_dir/src/proto_adapters/dragon_wax_adapter.cc \
- 倍增求LCA学习笔记(洛谷 P3379 【模板】最近公共祖先(LCA))
倍增求\(LCA\) 倍增基础 从字面意思理解,倍增就是"成倍增长". 一般地,此处的增长并非线性地翻倍,而是在预处理时处理长度为\(2^n(n\in \mathbb{N}^+)\ ...
- NOIP2018普及T2暨洛谷P5016 龙虎斗
题目链接:https://www.luogu.org/problemnew/show/P5016 分析: 这是一道模拟题.看到题目,我们首先要把它细致的读明白,模拟题特别考察细节,往往会有想不到的坑点 ...
- C#4.0新增功能02 命名实参和可选实参
连载目录 [已更新最新开发文章,点击查看详细] C# 4 介绍命名实参和可选实参. 通过命名实参,你可以为特定形参指定实参,方法是将实参与该形参的名称关联,而不是与形参在形参列表中的位置关联. ...
- Spring Boot @Condition 注解,组合条件你知道吗
上一篇文章 你应该知道的 @ConfigurationProperties 注解的使用姿势,这一篇就够了 介绍了如何通过 @ConfigurationProperties 注解灵活读取配置属性,这篇文 ...
- 插入Oracle数据库后返回当前主键id
最近做一个spring版本3.0.4的老项目功能,应用场景要用到插入oracle表后返回主键ID拿来和其他表关联. 用oralce的可以一直用这种处理方式,高兼容低,搜索网上的资料都不能和这个Spri ...