POST на сервер, получить PDF, доставить пользователю w / jQuery - PullRequest
47 голосов
/ 02 февраля 2010

У меня есть ссылка, по которой пользователь нажимает, чтобы получить PDF. В jQuery я создаю ajax-вызов POST на сервер, чтобы получить PDF. PDF приходит ко мне с правильными заголовками содержимого и т. Д., Которые обычно приводят к тому, что браузер открывает плагин Reader или позволяет пользователю сохранить PDF.

Поскольку я получаю PDF с вызовом ajax, я не уверен, что делать с данными, полученными в обратном вызове OnSuccess. Как я могу передать данные, которые я получаю, в браузер и позволить ему делать то же, что и по умолчанию, с ответом в формате PDF?

Ответы [ 7 ]

50 голосов
/ 02 февраля 2010

Посмотрите на - Плагин jQuery для запроса Ajax-подобных загрузок файлов

Весь plugin - это всего лишь около 30 строк кода (включая комментарии).

Вызов очень похож на вызов jquery ajax.

$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );

Конечно, вы должны установить заголовки content-type и Content-Disposition на стороне сервера, как при любой такой загрузке.

В Java я бы сделал что-то вроде этого

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
31 голосов
/ 02 февраля 2010

Вам вообще не нужен jQuery. Просто отправьте POST через форму в обычном режиме, а на стороне сервера добавьте заголовок HTTP

Content-Disposition: attachment; filename="whatever.pdf"

Браузер выполнит свою работу по умолчанию.

В качестве альтернативы, если вы хотите быть более осторожным при сообщении о любых ошибках, которые могут возникнуть при создании PDF, вы можете сделать это. Отправьте ваши параметры на ваш сервер с помощью jQuery. На сервере сгенерируйте двоичный контент и кэшируйте его где-нибудь в течение нескольких минут, к которому можно получить доступ с помощью ключа, который вы указали в сеансе пользователя, и верните «успешный» ответ Ajax на вашу страницу (или, если произошла ошибка, верните «ошибка» ответ). Если страница возвращает ответ об успехе, она может сразу сделать что-то вроде:

window.location = "/get/my/pdf";

Затем сервер возвращает кэшированное содержимое PDF. Обязательно включите заголовок Content-Disposition, как указано выше.

4 голосов
/ 06 февраля 2013

Ответ с упоминанием «Плагин 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 и knockout, вызывающий WebAPI, MVC4 и nHibernate. Часть 'format = csv' строки запроса запускает MediaTypeFormatter для преобразования возвращаемых моделей в тип файла CSV. Если я отключу это, то получу модели обратно из API и смогу заполнить сетку Slick для отображения.

2 голосов
/ 17 сентября 2014

У меня была та же проблема, но сверху используйте RESTFUL webservice для этого и у меня есть сложный объект данных, который я должен опубликовать.

Мое решение: Как и плагин jQuery, я создаю временную формуляр и отправляю ее. Но я отправляю объект данных как параметр с содержимым 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 Провайдером:

Spring Config:

<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-адреса данных), а также для планшетов и смартфонов и не имеет проблем с всплывающими окнами

1 голос
/ 22 июня 2015

Плагин 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();
};
0 голосов
/ 08 мая 2013

Я не понимаю, почему вы хотите ajax-запрос к URL-адресу загрузки файла! Но если это больше похоже на то, как клиент сам генерирует некоторый контент для скачивания - используйте данные URI. Отлично работает для Chrome и Firefox 20+. Safari и IE нет! Если Flash разрешен, вы можете использовать загрузчик.

Ах, прочитав ваш код, я вижу, что вы хотите отправить кучу параметров. Ну, если строка запроса не становится слишком длинной (IE8- имеет ограничение 2083), почему бы просто не использовать привязку с правильным URL?

    $('a.export-csv').click( function (evt){
      linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
      return true;
    });

Вышеизложенное позволяет изменить URL-адрес до того, как произойдет событие по умолчанию (щелчок).

0 голосов
/ 25 апреля 2012

Я думаю, что лучше всего будет создать временный pdf-файл в папке загрузок, а затем загрузить файл с помощью всплывающего окна, содержащего iframe ... chrome загрузит его мгновенно, но я полагаю, что для других вариантов необходимо установить Acrobat Reader для просмотрите pdf, но вы также можете использовать FlashPaper:)

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