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

1cosmwyk  于 2022-12-16  发布在  Go
关注(0)|答案(4)|浏览(952)

在我的Vue应用程序中,我收到了一个blob形式的PDF,并希望使用浏览器的PDF查看器显示它。
我把它转换成一个文件,并生成一个对象url:

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

然后通过将该URL设置为object元素的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元素设置文件名?
[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
o0lyfsai

o0lyfsai1#

Chrome的扩展似乎依赖于URI中设置的 resource name,即protocol://domain/path/file.ext中的 * 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 );
}

在服务工作器 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 );
  })() );
});

Live example(源代码)

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

虽然它确实在对话框中正确设置了文件名,但在将文件保存到磁盘时,他们似乎无法检索文件。
他们似乎没有执行网络请求(因此我们的软件没有捕捉到任何东西),我真的不知道现在去哪里看。
不过,这可能是今后在这方面开展工作的良好基础。
还有一个解决方案,我没有花时间亲自检查,那就是运行你自己的pdf查看器。
Mozilla已经提供了基于js的插件pdf.js,所以从那里我们应该能够设置文件名(尽管我再一次没有在那里挖掘)。
最后一点,Firefox可以使用blobURI所指向的File对象的name属性,所以即使这不是OP所要求的,在FF中它所需要的只是

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

piztneat2#

在Chrome中,文件名是从URL派生的,所以只要你使用的是blob URL,简短的回答就是“不,你不能设置Chrome中显示的PDF对象的文件名。”你不能控制分配给blob URL的UUID,也不能使用object元素将其覆盖为页面名称。有可能在PDF中指定了一个标题,并且它将作为文档名出现在PDF查看器中,但在下载时您仍然会得到散列名。
这似乎是一种安全防范措施,但我不能肯定。
当然,如果您可以控制URL,则可以通过更改URL轻松设置PDF文件名。

qoefvg9y

qoefvg9y3#

我相信Kaiido's answer简要地表达了这里的最佳解决方案:
如果您的原始URI包含该文件名,最简单的方法可能是将对象的数据设置为您直接从中获取pdf的URI
特别是对于那些来自this similar question的用户,如果能更详细地描述一个特定的实现(适用于pdf),它将帮助我获得最佳的用户体验,特别是在提供动态生成的文件时。
这里的技巧是使用一个两步的过程,完美地模仿一个正常的链接或按钮点击。客户端必须(步骤1)请求文件生成并存储在服务器端足够长的时间,以便客户端(步骤2)请求文件本身。这需要您有一些机制支持文件在磁盘或缓存中的唯一标识。
如果没有这个过程,用户在文件生成过程中只会看到一个空白标签页,如果失败,他们只会看到浏览器的ERR_TIMED_OUT页面。即使成功,他们也会在PDF查看器标签页的标题栏中看到一个哈希值,并且保存对话框将具有与建议的文件名相同的哈希值。
下面是要做得更好的详细情况:

  • 您可以使用锚标签或按钮来表示“download”或“view in browser”元素
  • 客户端上的步骤1(共2步):该元素的click事件可以请求仅生成文件(不传输)。
  • 服务器上的步骤1(共2步):生成文件并保存它。2只返回文件名给客户端。
  • 客户端上的步骤2(共2步):
  • 如果在浏览器中查看文件,请使用生成请求返回的文件名调用window.open('view_file/<filename>?fileId=1')。这是间接控制选项卡标题和任何后续保存对话框中显示的文件名的唯一方法。
  • 如果正在下载,只需调用window.open('download_file?fileId=1')
  • 服务器上的步骤2(共2步):
    *view_filefilename,fileId)处理程序只需要使用fileId提供文件并忽略filename参数。在.NET中,可以使用 FileContentResult,如File(bytes, contentType);
    *download_filefileId)必须通过Content-Disposition标头设置文件名,如here所示。在.NET中,它是return File(bytes, contentType, desiredFilename);
    客户端下载示例:
download_link_clicked() {
                // show spinner   
                ajaxGet(generate_file_url,
                    {},
                    (response) => {
                        // success!                        
                        // the server-side is responsible for setting the name 
                        // of the file when it is being downloaded                         
                        window.open('download_file?fileId=1', "_blank");
                        // hide spinner
                    },
                    () => { // failure
                       // hide spinner
                       // proglem, notify pattern
                    },
                    null
                );

客户端视图示例:

view_link_clicked() { 
                // show spinner
                ajaxGet(generate_file_url,
                    {},
                    (response) => {
                        // success!
                        let filename = response.filename;      
                        // simplest, reliable method I know of for controlling 
                        // the filename of the PDF when viewed in the browser
                        window.open('view_file/'+filename+'?fileId=1')
                        // hide spinner
                    },
                    () => { // failure
                       // hide spinner
                       // proglem, notify pattern
                    },
                    null
                );
js5cn81o

js5cn81o4#

我正在使用库pdf-lib,您可以通过click here了解有关该库的更多信息。
我通过使用API**Document.setTitle(“一些你想要的标题文本”)**解决了这个问题的一部分,
浏览器正确显示了我的标题,但当点击下载按钮时,文件名仍然是以前的UUID。也许库中有其他API允许您修改下载文件名。

相关问题