我可以设置在 Chrome 中显示的 PDF 对象的文件名吗?

新手上路,请多包涵

在我的 Vue 应用程序中,我收到一个 PDF 作为 blob,并希望使用浏览器的 PDF 查看器显示它。

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

 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 / object 元素的文件名?

[编辑] 如果有帮助,响应具有以下相关标头:

 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

原文由 false_azure 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

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

因此,如果您的原始 URI 包含该文件名,最简单的方法可能是简单地将您的 data 转换为您直接从中获取 pdf 的 URI,而不是按照 Blob 的方式。

现在,有些情况无法完成,对于这些情况,有一种 复杂的方式,这可能在未来版本的 Chrome 中不起作用,并且可能不适用于其他浏览器,需要设置一个 Service Worker

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

为此,我们可以使用缓存 API,使用我们的 URL 将我们的文件作为请求存储在那里,然后从 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

 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 );
  })() );
});

现场示例来源

编辑:这实际上在 Chrome 中不起作用……

虽然它确实在对话框中正确设置了文件名,但在将文件保存到磁盘时他们似乎无法检索文件……

他们似乎没有执行网络请求(因此我们的软件没有捕捉到任何东西),我现在真的不知道去哪里看。

这仍然可能是未来在这方面工作的良好基础。


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

Mozilla 已经提供了基于 js 的插件 pdf.js ,所以我们应该可以从那里设置文件名(尽管我还没有在那里挖掘)。


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

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

原文由 Kaiido 发布,翻译遵循 CC BY-SA 4.0 许可协议

在 Chrome 中,文件名源自 URL,因此只要您使用的是 blob URL,简短的回答就是“不,您不能设置在 Chrome 中显示的 PDF 对象的文件名。”您无法控制分配给 blob URL 的 UUID,也无法使用 object 元素将其覆盖为页面名称。可能在 PDF 中指定了一个标题,该标题将作为文档名称出现在 PDF 查看器中,但您在下载时仍会得到哈希名称。

这似乎是一种安全预防措施,但我不能肯定地说。

当然,如果您可以控制 URL,则可以通过更改 URL 轻松设置 PDF 文件名。

原文由 Old Pro 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题