Wyślij na serwer, odbierz PDF, dostarcz do użytkownika w / jQuery

Mam link, który użytkownik kliknie, aby uzyskać plik PDF. W jQuery tworzę Post ajax call to the server to get the PDF. PDF przychodzi do mnie z poprawnymi nagłówkami treści itp., które normalnie spowodowałyby otwarcie przeglądarki wtyczki Reader lub umożliwienie użytkownikowi zapisania pliku PDF.

Ponieważ otrzymuję plik PDF z wywołaniem ajax, nie jestem pewien, co zrobić z danymi, które otrzymuję w wywołaniu zwrotnym OnSuccess. W jaki sposób mogę przekazać dane, które otrzymuję do przeglądarki i zezwolić na jej domyślne wykonanie coś z odpowiedzią PDF?

Author: bryanvick, 2010-02-02

7 answers

W ogóle nie potrzebujesz jQuery. Po prostu prześlij swój POST za pomocą formularza, a po stronie serwera dodaj nagłówek HTTP

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

Przeglądarka zrobi swoje domyślne działanie.

Alternatywnie, jeśli chcesz być bardziej ostrożny w zgłaszaniu błędów, które mogą wystąpić podczas generowania pliku PDF, możesz to zrobić. Opublikuj swoje parametry na serwerze za pomocą jQuery. Na serwerze Wygeneruj zawartość binarną i buforuj ją gdzieś przez kilka minut, dostępną za pomocą klucza, który umieścisz w sesji użytkownika i zwróci odpowiedź" sukces "Ajax na Twoją stronę(lub jeśli wystąpił błąd, zwróć odpowiedź "błąd"). Jeśli strona otrzyma odpowiedź na sukces, może natychmiast zrobić coś takiego:

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

Serwer zwraca następnie buforowaną zawartość PDF. Pamiętaj, aby dołączyć nagłówek Content-Disposition, jak powyżej.

 31
Author: Sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 18:40:01

Spójrz na - wtyczka jQuery do pobierania plików w stylu Ajax

Całość plugin to około 30 linijek kodu (łącznie z komentarzami).

Wywołanie jest dość podobne do wywołania jQuery ajax.

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

Oczywiście, musisz ustawić nagłówki content-type I Content-Disposition po stronie serwera, tak jak w przypadku każdego takiego pobrania.

W Javie zrobiłbym coś takiego

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
 50
Author: Vinodh Ramasubramanian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-02 18:43:46

ODPOWIEDŹ wspominająca "jQuery Plugin do żądania pobierania plików Ajax-like" sprawiła, że skierowałem się w dobrym kierunku, ale nie zadziałało całkowicie w mojej sytuacji, ponieważ mam złożony obiekt i tablicę obiektów do przekazania jako moje kryteria wyszukiwania / DANE filtra. Pomyślałem, że podzielę się moim kodem na wypadek, gdyby ktoś inny wpadł w tę sytuację.

$.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');

To prawdopodobnie nie robi wielkiej różnicy, ale aby zapewnić jakiś kontekst, mam javascript i knockout UI wywołanie do WebAPI, MVC4 i nHibernate. Część "format=csv" łańcucha zapytania uruchamia MediaTypeFormatter, aby przekonwertować zwrócone modele na typ pliku CSV. Jeśli to zostawię, odzyskam modele z API i mogę wypełnić zgrabną siatkę do wyświetlania.

 3
Author: Mark Seefeldt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 21:51:35

Miałem ten sam problem, ale na górze użyj RESTFUL webservice do tego i mieć złożony obiekt danych, który muszę opublikować.

Moje rozwiązanie: podobnie jak wtyczka jQuery buduję szablon temp i przesyłam go. Ale obiekt danych wysyłam jako parametr z zawartością json (używam tutaj AngularJS ale powinien też działać z 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();

Po stronie serwera używamy CXF REST Service z JACKSON Provider:

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>

W kontrolerze wyodrębniłem param i przekształcił go z powrotem do Pojo Javy:

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;
    }
}

W PrintService buduję plik binarny pdf i odpowiedź:

@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();
}

To rozwiązanie działa na wszystkich przeglądarkach (nawet dla IE9, które nie mogą obsługiwać adresów URL danych) oraz na tabletach i smartfonach i nie ma problemów z popupblockerami

 2
Author: Anti-g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-17 13:12:09

Wtyczka jQuery do żądania pobierania plików podobnych do Ajax to-zasadniczo-tworzenie formularza, dodawanie danych postu jako ukrytych pól, dodawanie ich do treści strony, przesyłanie i usuwanie.

W moim przypadku nie miałem formularza, tylko fragment danych do opublikowania w takim stanie, w jakim był. To spowodowało następujące rozwiązanie. Po stronie serwera mogę uzyskać dane po prostu odczytując parametr "data" z żądania i DEKODUJĄC go 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();
};
 1
Author: MichaelK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-04 07:20:59

Nie rozumiem, dlaczego chcesz żądanie ajax do pliku URL pobierania! Ale jeśli jest to bardziej jak klient sam generuje jakąś zawartość do pobrania-użyj Uri danych. Działa doskonale dla Chrome i Firefox 20+. Safari i IE nie! Jeśli Flash jest dozwolony, możesz użyć downloadifier.

Po przeczytaniu Twojego kodu widzę, że chcesz wysłać kilka parametrów. No chyba, że ciąg zapytania jest zbyt długi (IE8 - ma limit 2083) dlaczego po prostu nie użyć anchora z odpowiednim adresem url?
    $('a.export-csv').click( function (evt){
      linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
      return true;
    });

Powyższe umożliwia zmianę adresu URL przed wystąpieniem domyślnego zdarzenia (kliknięcia).

 0
Author: Ustaman Sangat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-08 03:18:59

Myślę, że najlepiej będzie utworzyć tymczasowy plik pdf w folderze Pobrane, a następnie załadować plik za pomocą pop-up z iframe.. chrome załaduje go natychmiast, ale przypuszczam, że dla innych wariantów Acrobat reader musi być zainstalowany, aby wyświetlić pdf, ale znowu możesz użyć FlashPaper zbyt:)

 -1
Author: A Malik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-25 10:04:56