POST到服务器,接收PDF,交付给用户w / jQuery
我有一个用户点击获取PDF的链接。 在jQuery中,我创build一个POST ajax调用服务器来获取PDF。 PDF带给我正确的内容头等,这通常会导致浏览器打开Reader插件,或允许用户保存PDF。
由于我得到PDF的w / ajax调用,我不知道如何处理我在OnSuccesscallback中获得的数据。 如何将我收到的数据提供给浏览器,并允许其使用PDF响应来执行默认操作?
你根本不需要jQuery。 通常通过表单提交您的POST,并在服务器端添加HTTP标头
Content-Disposition: attachment; filename="whatever.pdf"
浏览器将执行其默认的事情。
或者,如果您想要更加小心地报告在PDF生成过程中可能发生的任何错误,您可以执行此操作。 用jQuery将你的参数发送到你的服务器。 在服务器上,生成二进制内容并将其caching在某个地方几分钟,可以通过放入用户会话的键访问,并向页面返回“成功”的Ajax响应(或者如果出现错误,则返回“错误”响应)。 如果页面取回成功响应,则可以立即执行如下操作:
window.location = "/get/my/pdf";
服务器然后返回caching的PDF内容。 请确保包含Content-Disposition标题,如上所述。
看看 – jQuery插件用于请求类似Ajax的文件下载
整个plugin
只有大约30行代码(包括注释)。
这个调用与jquery ajax调用非常相似。
$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );
当然,你必须像在任何这样的下载中一样,在服务器端设置内容types和内容处理标题。
在Java中,我会做这样的事情
response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
提到“用于请求类似Ajax的文件下载的jQuery插件”的答案让我朝着正确的方向前进,但是它并不完全适用于我的情况,因为我有一个复杂的对象和对象数组作为我的search条件/过滤数据。 我想我会分享我的代码,以防其他人也遇到这种情况。
$.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和敲除UI调用WebAPI,MVC4和nHibernate。 查询string的“format = csv”部分触发MediaTypeFormatter将返回的模型转换为CSV文件types。 如果我把它closures,那么我从API获取模型,并可以填充一个Slick网格来显示。
我有同样的问题,但最重要的是使用RESTFUL webservice
为此,并有一个复杂的数据对象,我必须发布。
我的解决scheme:像jQuery插件我build立一个临时forms并提交。 但我发送数据对象作为参数与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();
在服务器端,我们使用带有JACKSON
提供程序的CXF REST Service
:
springconfiguration:
<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>
在控制器中,我提取param并将其转换回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中,我构buildpdf二进制文件和响应:
@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(); }
这个解决scheme适用于所有的浏览器(即使IE9无法处理数据url),在平板电脑和智能手机上,它与popup式窗口拦截器没有问题
用于请求类似Ajax的文件下载的jQuery插件基本上是创build一个表单,将后期数据添加为隐藏字段,将其添加到页面主体,提交并删除它。
在我的情况下,我没有一个表格,只有大量的数据发布,因为它是。 这是为以下解决scheme。 在服务器端,我可以通过从请求中读取“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(); };
我不明白你为什么要一个文件下载url的ajax请求! 但是,如果它更像客户端本身生成一些内容下载 – 使用数据uri。 适用于Chrome和Firefox 20+。 Safari和IE不是! 如果Flash被允许,你可以使用下载器。
读完你的代码后,我看到你想发送一堆参数。 那么除非查询string太长(IE8-有2083的限制),为什么不简单地使用具有适当的URL的锚呢?
$('a.export-csv').click( function (evt){ linkEl.attr('href','/export?' + encodeURIComponent(formQueryString())); return true; });
以上允许您在默认事件(点击)发生之前更改URL。
我认为最好的办法是在下载文件夹中创build一个临时pdf文件,然后使用带有iframe的popup窗口来加载文件。铬会立即加载,但我想对于其他变体Acrobat阅读器必须安装以查看pdf但是你也可以使用FlashPaper 🙂