it-swarm.com.de

Kann ich den Dateinamen eines PDF Objekt in Chrome angezeigt?

In meiner Vue-App erhalte ich ein PDF als Blob und möchte es mit dem Browser PDF des Browsers anzeigen.

Ich konvertiere es in eine Datei und generiere eine Objekt-URL:

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

Dann zeige ich es an, indem ich diese URL als data-Attribut eines Objektelements setze.

<object
  :data="invoiceUrl"
  type="application/pdf"
  width="100%"
  style="height: 100vh;">
</object>

Der Browser zeigt dann den PDF mit dem Viewer PDF an. In Chrome wird jedoch der von mir angegebene Dateiname (hier mein Dateiname.pdf) nicht verwendet: In der Titelleiste des PDF - Viewers wird ein Hash angezeigt, und wenn ich die Datei mit herunterlad Entweder "Rechtsklick -> Speichern unter ..." oder die Steuerelemente des Viewers, es speichert die Datei mit dem Blob-Hash (cda675a6-10af-42f3-aa68-8795aa8c377d oder ähnlich).

Der Viewer und der Dateiname funktionieren wie in Firefox gehofft; Nur in Chrome wird der Dateiname nicht verwendet.

Gibt es eine Möglichkeit, mithilfe von nativem Javascript (einschließlich ES6, aber keine Drittanbieter-Abhängigkeiten außer Vue) den Dateinamen für ein Blob-/Objektelement in Chrome festzulegen?

[edit] Wenn es hilft, hat die Antwort die folgenden relevanten Kopfzeilen:

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
5
false_azure

Die Chrome-Erweiterung scheint auf dem in der URI festgelegten Ressourcennamen zu beruhen, d. H. Dem file.ext in protocol://domain/path/file.ext.

Wenn Ihre ursprüngliche URI diesen Dateinamen enthält, ist es möglicherweise am einfachsten, das data Ihres <object> zu der URI zu machen, von der Sie die PDF-Datei direkt abgerufen haben, anstatt den Weg des Blobs zu gehen.

Es gibt Fälle, in denen dies nicht möglich ist, und für diese gibt es einen verschlungenen Weg , der in zukünftigen Versionen von Chrome möglicherweise nicht funktioniert. und wahrscheinlich nicht in anderen Browsern, für die ein Service Worker eingerichtet werden muss.

Wie bereits erwähnt, analysiert Chrome die URI auf der Suche nach einem Dateinamen. Wir müssen also eine URI mit diesem Dateinamen erstellen, die auf unser BlobURI verweist.

Und das zu können, das ist der einzige Weg, den ich jetzt gefunden habe

  1. Stellen Sie aus dem Dokument eine POST Anfrage, die den Blob an unseren ServiceWorker sendet.
  2. Cachen Sie im ServiceWorker den gesendeten Blob
  3. Geben Sie vom ServiceWorker noch eine neue, gefälschte URI zurück, die wir mit dem in 2. zwischengespeicherten Blob abbilden
  4. Legen Sie im Dokument das src eines <iframe> fest1 zu dieser gefälschten URI.
  5. Fangen Sie die Anfrage vom ServiceWorker ab und senden Sie stattdessen unseren zwischengespeicherten Blob.
  6. Genießen Sie aus dem Dokument.

1. Ich konnte die Anfragen von einem <object> -Tag in Chrome nicht sehen, daher ist es wahrscheinlich besser, hier einen Iframe zu verwenden (hätte sowieso ein besseres Ergebnis in IE auch) .

Oder im Code,

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

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

Ich konnte leider keinen ServiceWorker auf plnkr.co zum Laufen bringen, aber Sie können immer noch das ganze hier einrichten finden, das Sie auf Ihren localhost kopieren können sollten.


Eine andere Lösung, für die ich mir nicht die Zeit genommen habe, es selbst zu überprüfen, wäre, einen eigenen PDF-Viewer zu verwenden.

Mozilla hat sein js-basiertes Plugin pdf.js verfügbar gemacht, daher sollten wir in der Lage sein, den Dateinamen festzulegen (obwohl ich dort noch einmal nicht nachgesehen habe).


Und als letzte Anmerkung kann Firefox die name -Eigenschaft eines File -Objekts verwenden, auf das ein blobURI zeigt. Also, obwohl es nicht das ist, wonach OP gefragt hat, in FF ist alles, was es benötigt

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

Wenn Sie die Ressource über Ihren eigenen Server anfordern, können Sie den Antwortheader Content-Disposition verwenden, um den Dateinamen in der Antwort zu übergeben.

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

Sie können es durch Ihren Dateinamen und die Erweiterung ersetzen. Sie können sich diesen link anschauen, um diese Kopfzeile weiter zu erkunden.

0
Pranay Tripathi

In Chrome wird der Dateiname von der URL abgeleitet. Solange Sie eine Blob-URL verwenden, lautet die kurze Antwort "Nein, Sie können den Dateinamen eines in Chrome angezeigten PDF -Objekts nicht festlegen." Sie haben keine Kontrolle über die der Blob-URL zugewiesene UUID, und Sie haben keine Möglichkeit, dies als Namen der Seite mithilfe des Elements object zu überschreiben. Es ist möglich, dass innerhalb von PDF ein Titel angegeben wird, der im Dokument PDF als Dokumentname angezeigt wird, aber beim Herunterladen immer noch den Hash-Namen erhalten. 

Dies scheint eine Sicherheitsvorkehrung zu sein, aber ich kann es nicht mit Sicherheit sagen.

Wenn Sie die URL steuern können, können Sie den Dateinamen PDF natürlich durch Ändern der URL festlegen. 

0
Old Pro