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

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

问题描述

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

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

我将其转换为文件,并生成对象网址:

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除外,但没有第三方依赖)来设置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.ext protocol://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版本中使用,并且可能无法在其他浏览器中使用,这需要设置服务工作者.

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,指向我们的BlobURI.

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 BlobURI.

要做到这一点,我目前发现的唯一方法是

And to be able to do it, the only way I found for now, is to

  1. 从文档中发出POST请求,该请求会将Blob发送到我们的ServiceWorker.
  2. 从ServiceWorker中,缓存已发送的Blob
  3. 还是从ServiceWorker那里返回一个新的伪URI,我们将使用它在 2中缓存的Blob进行映射.
  4. 从文档中,将< iframe> 1 src设置为该伪造的URI.
  5. 从ServiceWorker中捕获请求,然后发送我们的缓存Blob.
  6. 从文档中尽情享受.
  1. From the document, make a POST request, which will send the Blob to our ServiceWorker.
  2. From the ServiceWorker, cache the Blob that got sent
  3. Still from the ServiceWorker, return a new, fake URI, that we will map with the Blob cached in 2.
  4. From the document, set the src of an <iframe>1 to that fake URI.
  5. From he ServiceWorker, catch the request and send our cached Blob instead.
  6. From the document, enjoy.

1. 我无法在Chrome中看到从< object>标记发出的请求,因此在这里使用iframe可能更好(本来会更好)还是会导致IE).

或者在代码中

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

In the 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,但是您仍然可以找到整个

I was unfortunately unable to make a ServiceWorker work on plnkr.co, but you can still find the whole setup here that you should be able to copy to your localhost.

另一种解决方案是运行您自己的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天全站免登陆