POST到服务器,接收PDF,传递给用户w / jQuery

时间:2010-02-02 18:26:31

标签: jquery ajax pdf post

我有一个用户点击以获取PDF的链接。在jQuery中,我创建一个POST ajax调用服务器来获取PDF。 PDF带有正确的内容标题等,通常会导致浏览器打开Reader插件,或允许用户保存PDF。

由于我收到带有ajax调用的PDF,我不知道如何处理我在OnSuccess回调中获得的数据。如何将我收到的数据提供给浏览器并允许它使用PDF响应进行默认操作?

7 个答案:

答案 0 :(得分:50)

看看 - jQuery Plugin for Requesting Ajax-like File Downloads

整个plugin只有大约30行代码(包括评论)。

该调用与jquery ajax调用非常相似。

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

当然,您必须像在任何此类下载中一样在服务器端设置内容类型和内容处置标头。

在java中我会做这样的事情

response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");

答案 1 :(得分:31)

你根本不需要jQuery。只需通过表单正常提交您的POST,并在服务器端添加HTTP标头

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

浏览器将执行默认操作。

或者,如果您想要更加谨慎地报告PDF生成期间可能发生的任何错误,您可以执行此操作。使用jQuery将参数发布到服务器。在服务器上,生成二进制内容并将其缓存在某处几分钟,可通过您放入用户会话的密钥访问,并向您的页面返回“成功”Ajax响应(或者如果出现错误,则返回“错误”回应)。如果页面返回成功响应,它可以立即执行以下操作:

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

然后,服务器返回缓存的PDF内容。请务必包含Content-Disposition标头,如上所述。

答案 2 :(得分:4)

提到“请求类似Ajax的文件下载的jQuery插件”的答案让我朝着正确的方向前进,但它并没有完全适用于我的情况,因为我有一个复杂的对象和一组对象作为我的传递搜索条件/过滤数据。我想我会分享我的代码以防其他人遇到这种情况。

$.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 UI调用WebAPI,MVC4和nHibernate。查询字符串的'format = csv'部分触发MediaTypeFormatter将返回的模型转换为CSV文件类型。如果我将其关闭,那么我将从API返回模型,并可以填充Slick网格进行显示。

答案 3 :(得分:2)

我有同样的问题,但最重要的是使用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 ServiceJACKSON提供商:

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)以及平板电脑和智能手机也适用于弹出窗口阻止程序

答案 4 :(得分:1)

请求类似Ajax的文件下载的jQuery插件 - 实质上 - 创建表单,将帖子数据添加为隐藏字段,将其添加到页面正文,提交并删除它。

在我的情况下,我没有表格,只有一大块数据要发布。这为以下解决方案做出了贡献。在服务器端,我可以通过简单地读取&#34;数据&#34;来获取数据。来自请求的参数和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();
};

答案 5 :(得分:0)

我无法理解为什么你想要一个文件下载URL的ajax请求!但如果它更像客户端本身生成一些内容供下载 - 使用数据uri。适用于Chrome和Firefox 20+。 Safari和IE NOT!如果允许Flash,则可以使用下载程序。

看完你的代码后,我发现你想发送一堆参数。除非查询字符串太长(IE8-的限制为2083),否则为什么不简单地使用具有正确URL的锚?

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

以上允许您在默认事件(点击)发生之前更改URL。

答案 6 :(得分:-1)

我认为最好的方法是在downloads文件夹中创建一个临时pdf文件,然后使用带有iframe的弹出窗口加载文件.. chrome会立即加载它但我想其他变种必须安装Acrobat reader查看pdf,但你也可以使用FlashPaper:)