У меня есть одностраничное веб-приложение на основе jquery. Он связывается с веб-сервисом RESTful через вызовы AJAX.
Я пытаюсь сделать следующее:
- Отправьте сообщение POST, содержащее данные JSON, в URL-адрес REST.
- Если в запросе указан ответ JSON, возвращается JSON.
- Если в запросе указан ответ PDF / XLS / etc, возвращается загружаемый двоичный файл.
У меня сейчас работают 1 и 2, и клиентское приложение jquery отображает возвращенные данные на веб-странице, создавая элементы DOM на основе данных JSON. У меня также есть # 3, работающий с точки зрения веб-сервиса, то есть он создаст и вернет двоичный файл, если ему будут заданы правильные параметры JSON. Но я не уверен, что лучший способ справиться с # 3 в клиентском JavaScript-коде.
Можно ли получить загружаемый файл обратно с помощью вызова ajax, как это? Как получить браузер для загрузки и сохранения файла?
$.ajax({
type: "POST",
url: "/services/test",
contentType: "application/json",
data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
dataType: "json",
success: function(json, status){
if (status != "success") {
log("Error loading data");
return;
}
log("Data loaded!");
},
error: function(result, status, err) {
log("Error loading data");
return;
}
});
Сервер отвечает следующими заголовками:
Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)
Другая идея состоит в том, чтобы сгенерировать PDF-файл и сохранить его на сервере и вернуть JSON, содержащий URL-адрес файла. Затем выполните другой вызов в обработчике успеха ajax, чтобы сделать что-то вроде следующего:
success: function(json,status) {
window.location.href = json.url;
}
Но это означает, что мне нужно будет сделать более одного вызова на сервер, и мой сервер должен будет создавать загружаемые файлы, хранить их где-то, а затем периодически очищать эту область хранения.
Должен быть более простой способ сделать это. Идеи?
РЕДАКТИРОВАТЬ: После просмотра документов для $ .ajax, я вижу, что ответ dataType может быть только одним из xml, html, script, json, jsonp, text
, поэтому я предполагаю, что нет способа напрямую загрузить файл с помощью запроса ajax, если я не внедряю двоичный файл в использование Схема URI данных, предложенная в ответе @VinayC (что я не хочу делать).
Итак, я думаю, что мои варианты:
Не используйте ajax, вместо этого отправьте сообщение формы и вставьте мои данные JSON в значения формы. Вероятно, придется возиться со скрытыми фреймами и тому подобное.
Не используйте ajax, а вместо этого преобразуйте мои данные JSON в строку запроса для создания стандартного запроса GET и задайте для window.location.href этот URL. Может потребоваться использовать event.preventDefault () в моем обработчике кликов, чтобы браузер не менял URL приложения.
Используйте мою другую идею выше, но дополненную предложениями из ответа @naikus. Отправьте запрос AJAX с некоторым параметром, который позволяет веб-сервису узнать, что он вызывается с помощью вызова ajax. Если веб-служба вызывается из вызова ajax, просто верните JSON с URL-адресом сгенерированного ресурса. Если ресурс вызывается напрямую, верните фактический двоичный файл.
Чем больше я об этом думаю, тем больше мне нравится последний вариант. Таким образом, я могу получить информацию о запросе (время генерации, размер файла, сообщения об ошибках и т. Д.), И я могу обработать эту информацию перед началом загрузки. Недостатком является дополнительное управление файлами на сервере.
Есть ли другие способы сделать это? Какие-нибудь плюсы / минусы этих методов я должен знать?
источник
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url);
Простой способ получить те же результаты. Поместите заголовок в файл php. Не нужно отправлять ajax или получать запросыОтветы:
Решение letronje работает только для очень простых страниц.
document.body.innerHTML +=
берет HTML-текст тела, добавляет HTML-код iframe и устанавливает innerHTML страницы в эту строку. Это, среди прочего, уничтожит любые привязки событий на вашей странице. Создайте элемент и используйтеappendChild
вместо него.Или используя jQuery
Что это на самом деле делает: выполните запись в /create_binary_file.php с данными в переменной postData; если этот пост завершается успешно, добавьте новый iframe в тело страницы. Предполагается, что ответ из /create_binary_file.php будет содержать значение 'url', которое является URL-адресом, с которого можно загрузить сгенерированный файл PDF / XLS / etc. Добавление iframe на страницу, которая ссылается на этот URL, приведет к тому, что браузер предложит пользователю загрузить файл, предполагая, что веб-сервер имеет соответствующую конфигурацию MIME-типа.
источник
+=
и я обновлю свое приложение соответственно. Спасибо!Resource interpreted as Document but transferred with MIME type application/pdf
. Тогда это также предупреждает меня, что файл может быть опасным. Если я захожу на retData.url напрямую, никаких предупреждений или проблем.Я играл с другим вариантом, который использует капли. Мне удалось получить его для загрузки текстовых документов, и я загрузил PDF (однако они повреждены).
Используя API BLOB-объектов, вы сможете сделать следующее:
Это IE 10+, Chrome 8+, FF 4+. См. Https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL.
Он будет загружать только файлы в Chrome, Firefox и Opera. При этом используется атрибут загрузки тега привязки, чтобы браузер загружал его.
источник
click
:window.URL.revokeObjectURL(link.href);
Я знаю это старое, но я думаю, что нашел более элегантное решение. У меня была точно такая же проблема. Проблема с предложенными решениями заключалась в том, что все они требовали сохранения файла на сервере, но я не хотел сохранять файлы на сервере, потому что это вызывало другие проблемы (безопасность: доступ к файлу мог получить неаутентифицированные пользователи, очистка: как и когда вы избавляетесь от файлов). И, как и вы, мои данные были сложными, вложенными объектами JSON, которые было бы сложно поместить в форму.
Я создал две серверные функции. Первый подтвердил данные. Если произошла ошибка, она будет возвращена. Если это не было ошибкой, я вернул все параметры, сериализованные / закодированные в виде строки base64. Затем на клиенте у меня есть форма, в которой есть только один скрытый ввод и сообщения для второй функции сервера. Я установил скрытый ввод в строку base64 и отправил формат. Вторая серверная функция декодирует / десериализует параметры и генерирует файл. Форма может быть отправлена в новом окне или в фрейме на странице, и файл откроется.
Требуется немного больше работы и, возможно, немного больше обработки, но в целом я почувствовал себя намного лучше с этим решением.
Код находится в C # / MVC
на клиенте
источник
Есть более простой способ, создать форму и опубликовать ее, это рискует сбросить страницу, если возвращаемый тип MIME - это то, что откроет браузер, но для CSV и тому подобного он идеален.
Пример требует подчеркивания и jquery
Для таких вещей, как HTML, текст и тому подобное, убедитесь, что mimetype - это что-то вроде application / octet-stream.
PHP-код
источник
Короче говоря, нет более простого способа. Вам нужно сделать еще один запрос к серверу, чтобы показать файл PDF. Хотя есть несколько альтернатив, но они не идеальны и не будут работать во всех браузерах:
источник
Content-Disposition: attachment;filename="file.txt"
), но я действительно хочу попробовать этот подход в следующий раз. Ранее я использовалURI
данные для миниатюр, но мне никогда не приходило в голову использовать их для загрузки - спасибо, что поделились этим самородком.Прошло много времени с тех пор, как этот вопрос был задан, но у меня была такая же проблема, и я хочу поделиться своим решением. Он использует элементы из других ответов, но я не смог найти его полностью. Он не использует форму или iframe, но требует пару запросов post / get. Вместо сохранения файла между запросами, он сохраняет данные поста. Это кажется простым и эффективным.
клиент
сервер
источник
источник
Не совсем ответ на оригинальную статью, а быстрое и грязное решение для публикации json-объекта на сервере и динамической генерации загрузки.
JQuery на стороне клиента:
..и затем декодируем json-строку на стороне сервера и устанавливаем заголовки для загрузки (пример PHP):
источник
Я думаю, что лучший подход - это использовать комбинацию. Ваш второй подход кажется элегантным решением, когда задействованы браузеры.
Так что в зависимости от того, как сделан звонок. (будь то браузер или вызов веб-службы) вы можете использовать комбинацию этих двух способов: отправлять URL-адрес в браузер и отправлять необработанные данные любому другому клиенту веб-службы.
источник
Я не спал уже два дня, пытаясь выяснить, как загрузить файл с помощью jquery с помощью вызова ajax. Вся поддержка, которую я получил, не могла помочь моей ситуации, пока я не попробую это.
Сторона клиента
Сторона сервера
Удачи.
источник
Нашел его где-то давным-давно, и он работает отлично!
источник
Другой подход, вместо сохранения файла на сервере и его извлечения, заключается в использовании .NET 4.0+ ObjectCache с коротким сроком действия до второго действия (когда он может быть окончательно выгружен). Причина, по которой я хочу использовать JQuery Ajax для вызова, заключается в том, что он асинхронный. Создание моего динамического файла PDF занимает довольно много времени, и в течение этого времени я отображаю диалоговое окно с вращающимся вертелом (оно также позволяет выполнять другую работу). Подход с использованием данных, возвращаемых в «success:», для создания BLOB-объектов не работает надежно. Это зависит от содержимого файла PDF. Он легко искажается данными в ответе, если он не полностью текстовый, и это все, с чем может работать Ajax.
источник
Решение
Вложение Content-Disposition, кажется, работает для меня:
Временное решение
Применение / октет-поток
У меня было нечто подобное, происходящее со мной с JSON, для меня на стороне сервера я устанавливал заголовок self.set_header ("Content-Type", " application / json "), однако, когда я изменил его на:
Это автоматически загрузило это.
Также знайте, что для того, чтобы файл все еще сохранял суффикс .json, он вам понадобится в заголовке файла:
источник
С HTML5 вы можете просто создать якорь и нажать на него. Нет необходимости добавлять его в документ в детстве.
Все сделано.
Если вы хотите иметь специальное имя для загрузки, просто передайте его в
download
атрибуте:источник