POST на сервер, получать PDF, доставлять пользователю w/jQuery
У меня есть ссылка, которую пользователь нажимает, чтобы получить PDF файл. В jQuery я создаю ajax-вызов POST для сервера, чтобы получить PDF файл. PDF подходит ко мне с правильными заголовками содержимого и т.д., Которые обычно заставляют браузер открывать плагин Reader или позволять пользователю сохранять PDF файл.
Поскольку я получаю PDF с вызовом ajax, я не уверен, что делать с данными, которые я получаю в обратном вызове OnSuccess. Как я могу предоставить данные, которые я получаю в браузере, и позволить ему выполнять свою задачу по умолчанию с ответом PDF?
Ответы
Ответ 1
Вам вообще не нужен jQuery. Просто отправьте свой POST через форму, как правило, и на стороне сервера добавьте заголовок HTTP
Content-Disposition: attachment; filename="whatever.pdf"
Браузер выполнит свою задачу по умолчанию.
В качестве альтернативы, если вы хотите быть более внимательными к сообщениям о любых ошибках, которые могут возникнуть во время генерации PDF, вы можете это сделать. Отправьте свои параметры на свой сервер с помощью jQuery. На сервере сгенерируйте двоичный контент и кешируйте его где-то в течение нескольких минут, доступный с помощью ключа, который вы помещаете в сеанс пользователя, и возвращаете ответ "Ajax" на вашу страницу (или если произошла ошибка, верните ответ "ошибка" ). Если страница возвращает ответ успеха, он может сразу сделать что-то вроде:
window.location = "/get/my/pdf";
Затем сервер возвращает содержимое кэшированного PDF файла. Обязательно включите заголовок Content-Disposition, как указано выше.
Ответ 2
Взгляните на Плагин jQuery для запроса загрузки файлов Ajax
Весь plugin
составляет всего около 30 строк кода (включая комментарии).
Вызов довольно похож на вызов jquery ajax.
$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );
Конечно, вы должны установить заголовки содержимого и Content-Disposition на серверной стороне, как и для любой такой загрузки.
В java я бы сделал что-то вроде этого
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
Ответ 3
Ответ, в котором упоминается "плагин jQuery для запроса файлов Ajax файлов", заставил меня двигаться в правильном направлении, но это не сработало полностью для моей ситуации, так как у меня есть сложный объект и массив объектов, критерии поиска/данные фильтра. Я решил, что поделюсь своим кодом, если кто-то еще столкнется с этой ситуацией.
$.download = function (url, data, method) {
if (url && data) {
//convert the data object into input HTML fields
var inputs = '';
var convertToInput = function (key, keyStr, obj) {
if (typeof obj === 'undefined') {
return;
} else if (typeof obj === "object") {
for (var innerKey in obj) {
if (obj.hasOwnProperty(innerKey)) {
var innerKeyStr = '';
if (keyStr === '') {
innerKeyStr = innerKey.toString();
} else {
innerKeyStr = keyStr + "[" + innerKey.toString() + "]";
}
convertToInput(innerKey, innerKeyStr, obj[innerKey]);
}
}
return;
} else if ($.isArray(obj)) {
obj.forEach(function (item) {
convertToInput(key, keyStr + "[]", item);
});
return;
}
inputs += "<input type='hidden' name='" + keyStr + "' value='" + obj + "' />";
};
convertToInput(null, '', data);
//send request
jQuery('<form action="' + url + '" method="' + (method || 'post') + '">' + inputs + '</form>').appendTo('body').submit().remove();
};
};
$.download('/api/search?format=csv', searchData, 'POST');
Вероятно, это не имеет большого значения, но для обеспечения некоторого контекста у меня есть пользовательский интерфейс javascript и нокаута, который вызывается в WebAPI, MVC4 и nHibernate. Часть `format = csv 'строки запроса запускает MediaTypeFormatter для преобразования возвращенных моделей в тип файла CSV. Если я оставлю это, я верну модели обратно из API и смогу заполнить сетку Slick для отображения.
Ответ 4
У меня была та же проблема, но в верхней части используйте RESTFUL webservice
для этого и у меня есть сложный объект данных, который я должен опубликовать.
Мое решение:
как плагин jQuery, я создаю форму temp и отправлю ее. Но я отправляю объект данных в качестве параметра с содержимым json (я использую здесь AngularJS
, но он также должен работать с jQuery.param()
.)
JavaScript:
$('<form target="_blank" action="' + appConstants.restbaseurl + '/print/pdf" method="POST">' +
"<input name='data' value='" + angular.toJson($scope.versicherung) + "' />" +
'</form>').appendTo('body').submit().remove();
на стороне сервера мы используем CXF REST Service
с JACKSON
Provider:
Spring Конфигурация:
<jaxrs:server id="masterdataService" address="/">
<jaxrs:serviceBeans>
<ref bean="printRestServiceBean" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean class="de.controller.ExceptionHandler" />
</jaxrs:providers>
</jaxrs:server>
в контроллере я извлек параметр и преобразовал его обратно в Java Pojo:
package de.controller;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
@Path(Constants.PRINT_PATH)
@Consumes({ MediaType.APPLICATION_JSON, "application/x-www-form-urlencoded"})
@Produces("application/pdf; charset=UTF-8")
public class PrintRestController {
@Autowired
private PrintService printService;
@POST
@Produces("application/pdf")
@Path("/pdf")
public Response getPDF(@FormParam("data") String data) {
return printService.getPDF(json2Versicherung(data));
}
private Versicherung json2Versicherung(String data) {
Versicherung lVersicherung = null;
try {
ObjectMapper mapper = new ObjectMapper();
lVersicherung = mapper.readValue(data, Versicherung.class);
} catch(Exception e) {
LOGGER.error("PrintRestController.json2Versicherung() error", e);
}
return lVersicherung;
}
}
в PrintService я создаю pdf файл и ответ:
@Override
public Response getPDF(Versicherung pVersicherung) {
byte[] result = ... //build the pdf from what ever
ResponseBuilder response = Response.ok((Object) result);
response.header("Content-Disposition", "inline; filename=mypdf.pdf");
return response.build();
}
Это решение работает для всех браузеров (даже для IE9, которые не могут обрабатывать URL-адреса данных), так и на планшетах и смартфонах, и у него нет проблем с popupblockers
Ответ 5
Плагин jQuery для запроса Ajax файлов Загрузка файлов - по существу - создание формы, добавление данных сообщения в виде скрытых полей, добавление ее в тело страницы, ее отправку и удаление.
В моем случае у меня не было формы, и только фрагмент данных должен был быть размещен как есть. Это было сделано для следующего решения. На стороне сервера я могу получить данные, просто прочитав параметр "data" из запроса и URI-декодирования.
function postAndDownload(url, data) {
encodedData = encodeURIComponent(data);
$("<form>")
.attr("action", url)
.attr("method", "post")
.append(
$("input")
.attr("type", "hidden")
.attr("name", "data")
.attr("value", encodedData)
)
.appendTo("body")
.submit()
.remove();
};
Ответ 6
Я не понимаю, почему вам нужен запрос ajax для URL-адреса для загрузки файла! Но если это больше похоже на сам клиент, он создает некоторый контент для загрузки - используйте данные uri. Прекрасно работает для Chrome и Firefox 20+. Safari и IE NOT! Если Flash разрешен, вы можете использовать загрузчик.
Ah после прочтения вашего кода, я вижу, вы хотите отправить кучу параметров. Ну, если строка запроса слишком длинная (IE8- имеет ограничение 2083), почему бы просто не использовать якорь с правильным URL-адресом?
$('a.export-csv').click( function (evt){
linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
return true;
});
Вышеупомянутое позволяет вам изменить URL-адрес до события по умолчанию (щелчок).
Ответ 7
Я думаю, что лучше всего создать файл temp pdf в папке с загрузками, а затем загрузить файл, используя всплывающее окно с iframe.. Chrome будет загружать его мгновенно, но я полагаю, что для других вариантов Acrobat Reader должен быть установлен на просмотрите pdf, но снова вы можете использовать FlashPaper тоже:)