在我的Vue应用程序中,我收到一个PDF斑点,并希望使用浏览器的PDF查看器显示它。
我将其转换为文件,并生成对象网址:
const blobFile = new File([blob], `my-file-name.pdf`, { type: 'application/pdf' })
this.invoiceUrl = window.URL.createObjectURL(blobFile)
然后,通过将该URL设置为对象元素的data
属性来显示它。
<object
:data="invoiceUrl"
type="application/pdf"
width="100%"
style="height: 100vh;">
</object>
然后,浏览器使用PDF查看器显示PDF。但是,在Chrome中,未使用我提供的文件名(此处为my-file-name.pdf):我在PDF查看器的标题栏中看到一个哈希,并且在使用“右键单击”下载文件时->另存为...”或查看者的控件,它会使用blob的哈希(cda675a6-10af-42f3-aa68-8795aa8c377d
或类似名称)保存文件。
查看器和文件名可以像我在Firefox中所希望的那样工作;这只是不使用文件名的Chrome。
是否可以使用本机Javascript(包括ES6,但Vue除外,但没有第三方依赖)来设置Chrome中Blob /对象元素的文件名?
[edit]如果有帮助,则响应具有以下相关的标题:
Content-Type: application/pdf; charset=utf-8
Transfer-Encoding: chunked
Content-Disposition: attachment; filename*=utf-8''Invoice%2016246.pdf;
Content-Description: File Transfer
Content-Encoding: gzip
答案 0 :(得分:3)
Chrome的扩展名似乎依赖于URI中设置的资源名称,即file.ext
中的 protocol://domain/path/file.ext
。
因此,如果您的原始URI包含该文件名,那么最简单的方法可能就是将您的
现在,在某些情况下无法完成操作,因此,存在一种令人费解的方法,该方法可能无法在以后的Chrome版本中使用,并且可能无法在其他浏览器中使用,来设置Service Worker。
正如我们首先说的,Chrome浏览器会解析URI以查找文件名,因此我们要做的就是拥有一个带有该文件名的URI,指向我们的BlobURI。
要做到这一点,我目前发现的唯一方法是
1。 我无法在Chrome中看到来自
或者在代码中,
在 document.html
// register our ServiceWorker
navigator.serviceWorker.register('/sw.js')
.then(...
...
function displayRenamedPDF(file, filename) {
// we use an hard-coded fake path
// that we will check in every requests from the SW
const reg_path = '/nameForcer_register/'
// pass the filename
const url = reg_path + encodeURIComponent(filename);
const xhr = new XMLHttpRequest();
xhr.open('POST', url);
return new Promise((res, rej) => {
xhr.onload = e => {
const frame = document.createElement('iframe');
frame.src = xhr.response;
document.body.append(frame);
return frame;
};
xhr.send(file);
})
}
在ServiceWorker中 sw.js
self.addEventListener('fetch', function(event) {
const req = event.request,
url = new URL(req.url),
// parse the /path/ from every request url
pathes = url.pathname.split('/'),
// are we registering
nameRegIndex = pathes.indexOf('nameForcer_register'),
// or fetching
nameFetcherIndex = pathes.indexOf('nameForcer_fetch');
if(nameRegIndex > -1) { // register
event.respondWith(
req.blob() // grab the POSTed Blob
.then((blob) => {
const filename = pathes[nameRegIndex+1] || '';
// store in our db object
db[filename] = blob;
return filename;
})
.then((filename) =>
new Response('/nameForcer_fetch/' + filename)
)
);
}
else if(nameFetcherIndex > -1) { // fetch
const filename = pathes[nameFetcherIndex + 1];
const cached = db[filename];
// just for Firefox, Chrome doesn't care...
const headers = new Headers({
'Content-Disposition': 'inline; filename="' + decodeURIComponent(filename) + '"'
});
event.respondWith(
new Response(cached, {
headers: headers
})
);
delete db[filename]; // !! one time URI !!
}
else { // normal requests
event.respondWith(fetch(event.request))
}
});
很遗憾,我无法在plnkr.co上运行ServiceWorker,但仍然可以找到应该复制到本地主机的整个setup here。
另一种解决方案是运行您自己的pdf查看器,我没有花时间自己检查一下。
Mozilla已使其基于js的插件pdf.js可用,因此从那里我们应该能够设置文件名(即使我再次没有在那儿挖过)。
最后一点,Firefox能够使用blobURI指向的name
对象的File
属性。
因此,即使这不是OP要求的,在FF 中,所需的只是
const file = new File([blob], filename);
const url = new URL(blob);
object.data = url;
答案 1 :(得分:0)
如果要通过自己的服务器请求资源,则可以使用Content-Disposition
响应标头在响应中传递文件名。
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
您可以用文件名和扩展名替换它。您可以根据自己的需要查看此link,以进一步探索此标头。
答案 2 :(得分:0)
在Chrome中,文件名是从URL派生的,因此,只要您使用的是Blob URL,简短的回答是“否,您无法设置在Chrome中显示的PDF对象的文件名。”您无法控制分配给Blob URL的UUID,也无法使用'modified'
元素将其覆盖为页面名称。可能在PDF内指定了一个标题,该标题将在PDF查看器中显示为文档名称,但下载时仍会得到哈希名称。
这似乎是安全预防措施,但我不能肯定地说。
当然,如果您可以控制URL,则可以通过更改URL轻松设置PDF文件名。