Подтвердить что ты не робот

POST на сервер, получать PDF, доставлять пользователю w/jQuery

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

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

4b9b3361

Ответ 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 тоже:)