Могу ли я задать имя файла PDF-объекта, отображаемого в Chrome? - PullRequest
0 голосов
/ 30 ноября 2018

В моем приложении Vue я получаю PDF в виде большого двоичного объекта и хочу отобразить его с помощью обозревателя 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, и когда я загружаю файл, нажимая правой кнопкой мыши-> Сохранить как ... 'или элементы управления средства просмотра, он сохраняет файл с хэшем большого двоичного объекта (cda675a6-10af-42f3-aa68-8795aa8c377d или аналогичным).

Программа просмотра и имя файла работают так, как я надеялся в Firefox;это только Chrome, в котором имя файла не используется.

Есть ли способ, используя собственный Javascript (включая ES6, но без сторонних зависимостей, кроме Vue), чтобы задать имя файла для элемента blob / objectв Chrome?

[править] Если это помогает, ответ имеет следующие соответствующие заголовки:

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

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

В Chrome имя файла происходит от URL-адреса, поэтому, пока вы используете URL-адрес BLOB-объекта, короткий ответ «Нет, вы не можете установить имя файла PDF-объекта, отображаемого в Chrome».Вы не можете контролировать UUID, назначенный URL-адресу BLOB-объекта, и не можете переопределить его как имя страницы с помощью элемента object.Возможно, что внутри PDF-файла указан заголовок, который появится в средстве просмотра PDF в качестве имени документа, но вы все равно получите имя хеш-кода при загрузке.

Похоже, это мера безопасности, но я не могу сказать наверняка.

Конечно, если у вас есть контроль над URL, вы можете легко установить имя файла PDF, изменив URL.

0 голосов
/ 03 декабря 2018

Расширение Chrome зависит от имени ресурса , заданного в URI, то есть file.ext в protocol://domain/path/file.ext.

Так что, если ваш исходный URIсодержит это имя файла, проще всего было бы просто сделать ваши s data для URI, из которого вы получили pdf напрямую, вместо того, чтобы идти по пути Blob.

Теперь есть случаи, когда это невозможно сделать, и для них есть извилистый способ , который может не работать в будущих версиях Chrome и, вероятно, не в других браузерах.требуя установить Service Worker .

Как мы впервые сказали, Chrome анализирует URI в поисках имени файла, поэтому нам нужно иметь URI сэто имя файла, указывающее на наш BlobURI.

И чтобы сделать это, единственный способ, который я нашел на данный момент, это

  1. . Из документа сделайте запрос POST,который отправит BLOB-объект нашему ServiceWorker.
  2. Из ServiceWorker кэшируйте отправленный BLOB-объект
  3. Кадр из ServiceWorker, верните новый поддельный URI, который мы сопоставим с BLOB-объектомкэшируется в 2.
  4. Из документа установите src
  5. Из негоServiceWorker, перехватите запрос и отправьте вместо этого наш кэшированный BLOB-объект.
  6. Из документа наслаждайтесь.

1. Я не смог увидеть запросы, сделанные из тега в Chrome, поэтому, вероятно, лучше использовать здесь 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

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

Я, к сожалению, не смог заставить ServiceWorker работать на plnkr.co, но вы все равно можете найти всю настройку здесь , что вам следуетбыть в состоянии скопировать на ваш локальный хост.


И еще одно решение, которое я сам не потратил на проверку, - это запустить собственный просмотрщик PDF.

Mozillaсделал доступным свой плагин на основе js pdf.js , поэтому оттуда мы сможем установить имя файла (хотя я еще не копал там).


И, наконец, Firefox может использовать свойство name объекта File, на который указывает blobURI.Так что, хотя это не то, о чем просил OP, в FF все, что требуется, это

const file = new File([blob], filename);
const url = new URL(blob);
object.data = url;
0 голосов
/ 03 декабря 2018

Если вы запрашиваете ресурс через свой собственный сервер, вы можете использовать Content-Disposition заголовок ответа для передачи имени файла в ответе.

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

Вы можете заменить его на свое имя и расширение файла,Вы можете просмотреть эту ссылку , чтобы изучить этот заголовок в соответствии с вашими потребностями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...