我可以设置 Chrome 中显示的 PDF 对象的文件名吗? [英] Can I set the filename of a PDF object displayed in Chrome?

查看:179
本文介绍了我可以设置 Chrome 中显示的 PDF 对象的文件名吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 Vue 应用程序中,我收到一个 Blob 格式的 PDF,并希望使用浏览器的 PDF 查看器显示它.

In my Vue app I receive a PDF as a blob, and want to display it using the browser's PDF viewer.

我将其转换为文件,并生成一个对象 url:

I convert it to a file, and generate an object url:

const blobFile = new File([blob], `my-file-name.pdf`, { type: 'application/pdf' })
this.invoiceUrl = window.URL.createObjectURL(blobFile)

然后我通过将该 URL 设置为对象元素的 data 属性来显示它.

Then I display it by setting that URL as the data attribute of an object element.

<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 或类似内容)保存文件.

The browser then displays the PDF using the PDF viewer. However, in Chrome, the file name that I provide (here, my-file-name.pdf) is not used: I see a hash in the title bar of the PDF viewer, and when I download the file using either 'right click -> Save as...' or the viewer's controls, it saves the file with the blob's hash (cda675a6-10af-42f3-aa68-8795aa8c377d or similar).

查看器和文件名如我在 Firefox 中所希望的那样工作;只有 Chrome 没有使用文件名.

The viewer and file name work as I'd hoped in Firefox; it's only Chrome in which the file name is not used.

有什么方法可以使用原生 Javascript(包括 ES6,但没有除 Vue 之外的第 3 方依赖项)在 Chrome 中设置 blob/对象元素的文件名?

Is there any way, using native Javascript (including ES6, but no 3rd party dependencies other than Vue), to set the filename for a blob / object element in Chrome?

[edit] 如果有帮助,响应具有以下相关标题:

[edit] If it helps, the response has the following relevant headers:

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

推荐答案

Chrome 的扩展似乎依赖于 URI 中设置的资源名称,即 file.extprotocol://domain/path/file.ext 中.

Chrome's extension seems to rely on the resource name set in the URI, i.e the file.ext in protocol://domain/path/file.ext.

因此,如果您的原始 URI 包含该文件名,最简单的方法可能是简单地将您的 <object> 的 data 设置为您直接从中获取 pdf 的 URI,而不是采用 Blob 的方式.

So if your original URI contains that filename, the easiest might be to simply make your <object>'s data to the URI you fetched the pdf from directly, instead of going the Blob's way.

现在,有些情况是做不到的,对于这些情况,有一种复杂的方法,这可能在 Chrome 的未来版本中不起作用,也可能在其他浏览器中不起作用,需要设置 Service Worker.

Now, there are cases it can't be done, and for these, there is a convoluted way, which might not work in future versions of Chrome, and probably not in other browsers, requiring to set up a Service Worker.

正如我们首先所说,Chrome 解析 URI 以搜索文件名,所以我们要做的就是拥有一个 URI,该文件名指向我们的 blob://URI.

As we first said, Chrome parses the URI in search of a filename, so what we have to do, is to have an URI, with this filename, pointing to our blob:// URI.

为此,我们可以使用缓存 API,使用我们的 URL 将我们的文件作为请求存储在其中,然后从 ServiceWorker 的缓存中检索该文件.

To do so, we can use the Cache API, store our File as Request in there using our URL, and then retrieve that File from the Cache in the ServiceWorker.

或者在代码中,

从主页

// register our ServiceWorker
navigator.serviceWorker.register('/sw.js')
  .then(...
...

async function displayRenamedPDF(file, filename) {
  // we use an hard-coded fake path
  // to not interfere with legit requests
  const reg_path = "/name-forcer/";
  const url = reg_path + filename;
  // store our File in the Cache
  const store = await caches.open( "name-forcer" );
  await store.put( url, new Response( file ) );

  const frame = document.createElement( "iframe" );
  frame.width = 400
  frame.height = 500;
  document.body.append( frame );
  // makes the request to the File we just cached
  frame.src = url;
  // not needed anymore
  frame.onload = (evt) => store.delete( url );
}

在 ServiceWorker sw.js

In the ServiceWorker sw.js

self.addEventListener('fetch', (event) => {
  event.respondWith( (async () => {
    const store = await caches.open("name-forcer");
    const req = event.request;
    const cached = await store.match( req );
    return cached || fetch( req );
  })() );
});

现场示例(来源)

虽然在对话框中正确设置了文件名,但在将文件保存到磁盘时,他们似乎无法检索文件...
他们似乎没有执行网络请求(因此我们的软件没有捕捉到任何东西),我现在真的不知道该往哪里看.
不过,这可能是未来开展这方面工作的良好基础.

While it does set correctly the filename in the dialog, they seem to be unable to retrieve the file when saving it to the disk...
They don't seem to perform a Network request (and thus our SW isn't catching anything), and I don't really know where to look now.
Still this may be a good ground for future work on this.

我没有花时间自己检查的另一种解决方案是运行您自己的 pdf 查看器.

And an other solution, I didn't took the time to check by myself, would be to run your own pdf viewer.

Mozilla 已经提供了基于 js 的插件 pdf.js,所以我们从那里开始应该能够设置文件名(即使我再次没有在那里挖掘).

Mozilla has made its js based plugin pdf.js available, so from there we should be able to set the filename (even though once again I didn't dug there yet).

最后一点,Firefox 能够使用 blobURI 指向的 File 对象的 name 属性.因此,即使这不是 OP 所要求的,在 FF 中它所需要的只是

And as final note, Firefox is able to use the name property of a File Object a blobURI points to. So even though it's not what OP asked for, in FF all it requires is

const file = new File([blob], filename);
const url = new URL(blob);
object.data = url;

这篇关于我可以设置 Chrome 中显示的 PDF 对象的文件名吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆