0

Как создать PDF-файл из бинарной строки, полученной от веб-сервиса, с использованием JavaScript

1

Описание проблемы

Я пытаюсь создать PDF-файл из бинарного потока, который получаю в ответ на AJAX-запрос.

С помощью XmlHttpRequest я получаю следующие данные:

%PDF-1.4....
.....
....все данные, представляющие файл
....
%% EOF

Пока что я пробовал встроить свои данные через data:uri. Это работает нормально и без ошибок. К сожалению, это не срабатывает в IE9 и Firefox. Возможно, причина в том, что у этих браузеров есть проблемы с использованием data-uri.

Теперь я ищу какое-либо решение, которое будет работать во всех браузерах. Вот мой код:

// кодировка responseText 
pdfText = $.base64.decode($.trim(pdfText));

// Теперь pdfText содержит %PDF-1.4 ...... данные ...... %%EOF

var winlogicalname = "detailPDF";
var winparams = 'dependent=yes,locationbar=no,scrollbars=yes,menubar=yes,'+
                'resizable,screenX=50,screenY=50,width=850,height=1050';

var htmlText = '<embed width=100% height=100%'
                     + ' type="application/pdf"'
                     + ' src="data:application/pdf,'
                     + escape(pdfText)
                     + '"></embed>'; 

// Открыть PDF в новом окне браузера
var detailWindow = window.open ("", winlogicalname, winparams);
detailWindow.document.write(htmlText);
detailWindow.document.close();

Как я уже говорил, это работает хорошо в Opera и Chrome (Safari не тестировался). Используя IE или Firefox, открывается пустое новое окно.

Есть ли какое-либо решение, позволяющее создать PDF-файл в файловой системе для последующей загрузки пользователем? Мне нужно решение, которое будет работать во всех браузерах, по крайней мере в IE, FF, Opera, Chrome и Safari.

Я не имею прав на редактирование реализации веб-сервиса, поэтому решение должно быть клиентским. Есть идеи?

5 ответ(ов)

0

Чтобы создать PDF-файл на файловой системе и предоставить пользователю возможность его скачать, вы можете использовать следующий подход с помощью XMLHttpRequest. Установите responseType в blob и используйте атрибут download в элементе <a>, чтобы осуществить скачивание PDF-файла. Ниже представлен пример кода, который вы можете использовать:

var request = new XMLHttpRequest();
request.open("GET", "/path/to/pdf", true); 
request.responseType = "blob";
request.onload = function (e) {
    if (this.status === 200) {
        // Получен `blob`
        console.log(this.response);
        
        // Создание `objectURL` из полученного `blob` (.pdf)
        var file = window.URL.createObjectURL(this.response);
        var a = document.createElement("a");
        a.href = file;
        a.download = this.response.name || "detailPDF"; // Установка имени файла
        document.body.appendChild(a);
        a.click(); // Инициация скачивания
        
        // Удаление элемента `a` после диалога сохранения,
        // чтобы `window` снова получил фокус
        window.onfocus = function () {                     
          document.body.removeChild(a);
        }
    }
};
request.send();

Эта конструкция создаёт запрос к вашему серверу, получает PDF-файл в формате blob и инициирует его скачивание. Не забудьте заменить "/path/to/pdf" на действительный путь к вашему PDF-файлу.

0

Я понимаю, что это довольно старая тема, но вот решение, которое я разработал сегодня:

doSomethingToRequestData().then(function(downloadedFile) {
  // создаем элемент ссылки для скачивания
  var downloadLink      = document.createElement('a');
  downloadLink.target   = '_blank';
  downloadLink.download = 'имя_для_сохраненного_файла.pdf';

  // конвертируем загруженные данные в Blob
  var blob = new Blob([downloadedFile.data], { type: 'application/pdf' });

  // создаем объектный URL из Blob
  var URL = window.URL || window.webkitURL;
  var downloadUrl = URL.createObjectURL(blob);

  // задаем объектный URL как href ссылки
  downloadLink.href = downloadUrl;

  // добавляем ссылку в тело документа
  document.body.append(downloadLink);

  // инициируем клик по ссылке
  downloadLink.click();

  // очистка: удаляем элемент и отзываем объектный URL
  document.body.removeChild(downloadLink);
  URL.revokeObjectURL(downloadUrl);
}

Если у вас возникнут вопросы или потребуется дополнительная помощь, не стесняйтесь спрашивать!

0

Вы изменили код следующим образом:

var htmlText = '<embed width=100% height=100%'
                 + ' type="application/pdf"'
                 + ' src="data:application/pdf,'
                 + escape(pdfText)
                 + '"></embed>'; 

на

var htmlText = '<embed width=100% height=100%'
                 + ' type="application/pdf"'
                 + ' src="data:application/pdf;base64,'
                 + escape(pdfText)
                 + '"></embed>'; 

и это сработало для вас.

Вероятно, проблема заключалась в том, что вы не указывали правильный формат данных в строке base64. Когда вы добавили base64 в строку src, браузер правильно распознал кодировку данных как base64, что и привело к успешному отображению PDF. Убедитесь, что pdfText действительно содержит корректные данные в формате base64 для PDF, чтобы избежать возможных ошибок.

0

Ответ @alexandre с использованием base64 решает задачу.

Объяснение, почему это работает для IE, находится здесь:

https://en.m.wikipedia.org/wiki/Data_URI_scheme

В разделе 'формат', где указано:

Некоторые браузеры (Chrome, Opera, Safari, Firefox) принимают нестандартный порядок, если указаны оба параметра ;base64 и ;charset, в то время как Internet Explorer требует, чтобы спецификация charset предшествовала токену base64.

0

Ваш код на PHP для декодирования бинарных данных и отображения PDF-файла выглядит в целом правильно, но я хотел бы предложить несколько улучшений, чтобы убедиться, что все работает корректно.

  1. Убедитесь, что данные, которые вы декодируете, действительно являются корректными данными в формате base64. Если они испорчены или неполные, это может привести к ошибке в отображении PDF.

  2. В строке с Content-Length: можно добавить пробел после Content-Length:, иначе это может вызвать некоторые проблемы с заголовками.

  3. Проверьте, чтобы код выше не выводил никаких других текстов или пустых строк до отправки данных. Любые пробелы или строки могут испортить ответы HTTP.

Ниже приведен улучшенный вариант вашего кода:

<?php
$data = 'dfjhdfjhdfjhdfjhjhdfjhdfjhdfjhdfdfjhdf==blah...blah...blah..';

// Декодирование данных
$data = base64_decode($data);

// Проверка на успешное декодирование
if ($data === false) {
    die('Ошибка декодирования данных.');
}

// Отправка заголовков для PDF
header("Content-Type: application/pdf");
header("Content-Length: " . strlen($data));
header("Content-Disposition: inline; filename=label.pdf");

// Вывод данных
echo $data;
exit;
?>

Обратите внимание на следующие моменты:

  • Я добавил проверку на успешное декодирование данных — если данные не могут быть декодированы, код завершится с соответствующим сообщением об ошибке.
  • Вместо print использован echo, но это не критично — оба варианта работают.
  • Убедитесь, что до вызова header никаких данных не было выведено.

Попробуйте этот код, и если проблема сохраняется, проверьте, какие данные вы получаете от сервера для декодирования.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь