网页中直接下载 PDF 文件而不打开新的页面加载 PDF 文件
我们知道 <a>
元素有 download
属性,表示当前链接不是用来浏览的,而是用来下载的。它的值是一个字符串,表示用户下载得到的文件名。可是对于 PDF
文件,浏览器默认打开一个新的页面加载 PDF
文件,而不会直接下载该文件。
这时候我们需要将原来的用于下载的 url 进行转换,转换成一个 Blob
对象的 URL
。
一、用 Blob
对象来读写 PDF
文件
引入 Blob
对象,用 Blob
(Binary Large Object
二进制大型文件) 对象来读写 PDF
文件。
浏览器原生提供 Blob()
构造函数,用来生成实例对象。
new Blob(array [, options])
Blob
构造函数接受两个参数。第一个参数是数组,成员是字符串或二进制对象,表示新生成的 Blob
实例对象的内容;第二个参数是可选的,是一个配置对象,目前只有一个属性 type
,它的值是一个字符串,表示数据的 MIME
类型,默认是空字符串。
let htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
let myBlob = new Blob(htmlFragment, { type: 'text/html' });
上面代码中,实例对象 myBlob
包含的是字符串。生成实例的时候,数据类型指定为 text/html
。
下面是另一个例子,Blob
保存 JSON
数据。
let obj = { hello: 'world' };
let blob = new Blob([JSON.stringify(obj)], { type: 'application/json' });
blob; // Blob {size: 17, type: "application/json"}
对于 MIME
类型,需要选择适合二进制文件流的类型,而不是普通的文本类型:(MIME
类型)
浏览器通常使用
MIME
类型(而不是文件扩展名)来确定如何处理URL
,因此Web
服务器在响应头中添加正确的MIME
类型非常重要。如果配置不正确,浏览器可能会曲解文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。
还有一种很重要的 MIME
类型 application/octet-stream
这是应用程序文件的默认值。意思是 未知的应用程序文件 ,浏览器一般不会自动执行或询问执行。浏览器会像对待 设置了
HTTP
头Content-Disposition
值为attachment
的文件一样来对待这类文件。
二、通过 URL.createObjectURL()
方法将 Blob 对象转换成 url
URL.createObjectURL()
方法将流媒体文件生成一个 URL
字符串。这个字符串代表了 Blob
对象的 URL
。
该方法生成的 URL
就像下面的样子(以 blob:
开头的字符串)。
blob:http://localhost:3209/28c3a781-3492-4cff-82cc-2f72a0a7f245
至此我们就拿到了 Blob
对象的 URL
。
当我们拿到下载 PDF
文件的地址(url
)和 PDF
文件名(name
)后,先转换成二进制文件流的 url
,然后就可以下载该文件了。
handlePdfLink(url: string, name: string): void {
fetch(url, {
method: 'get'
})
.then(function (res) {
if (res.status !== 200) {
return res.json()
}
return res.arrayBuffer()
})
.then((blobRes) => {
// 生成 Blob 对象,设置 type 等信息
const e = new Blob([blobRes], {
type: 'application/octet-stream'
})
// 将 Blob 对象转为 url
this.blobLink = window.URL.createObjectURL(e)
this.downloadFile(this.blobLink, name)
}).catch(err => {
console.error(err)
})
}
上面代码中 arrayBuffer()
将产生一段二进制数据。Response.arrayBuffer()
arrayBuffer()
接受一个Response
流, 并等待其读取完成. 它返回一个promise
实例, 并resolve
一个ArrayBuffer
对象。
然后将文件的MIME
类型设置为 application/octet-stream
让浏览器不会自动执行或询问执行,装入 Blob
对象中进行读取文件的数据内容。
再使用 URL.createObjectURL()
方法,针对 Blob
对象生成一个临时 URL
,以便于某些 API
使用。这个 URL
以 blob:
开头,表明对应一个 Blob
对象,协议头后面是一个识别符,用来唯一对应内存里面的 Blob
对象。这一点与 data://URL
(URL
包含实际数据)和 file://URL
(本地文件系统里面的文件)都不一样。
最后我们添加 <a>
元素给它装入下载地址 url
和下载文件名 name
来下载 PDF
文件。
downloadFile(url: string, name: string): void {
if (url && url.trim()) {
let a = document.createElement('a');
a.href = url;
a.download = name || '未命名文件';
a.click();
window.URL.revokeObjectURL(this.blobLink);
} else {
this.msg.remove();
this.msg.error('文件下载路径不能为空!');
}
}
由于每次使用 URL.createObjectURL()
方法,都会在内存里面生成一个 URL
实例。如果不再需要该方法生成的 URL
字符串,为了节省内存,下载完成后可以使用 URL.revokeObjectURL()
方法释放这个实例。