POST 到服务器,接收 PDF,使用 jQuery 交付给用户
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2186562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
POST to server, receive PDF, deliver to user w/ jQuery
提问by bryanvick
I have a link that the user clicks to get a PDF. In jQuery, I create a POST ajax call to the server to get the PDF. The PDF comes to me with the correct content headers etc that would normally cause the browser to open the Reader plugin, or allow the user to save the PDF.
我有一个链接,用户单击该链接可以获取 PDF。在 jQuery 中,我创建了一个对服务器的 POST ajax 调用以获取 PDF。PDF带有正确的内容标题等,通常会导致浏览器打开阅读器插件,或允许用户保存PDF。
Since I am getting the PDF w/ an ajax call, I'm not sure what to do with the data that I get in the OnSuccess callback. How can I give the data I receive to the browser and allow it to do its default thing with the PDF response?
由于我使用 ajax 调用获取 PDF,因此我不确定如何处理我在 OnSuccess 回调中获取的数据。如何将我收到的数据提供给浏览器并允许它使用 PDF 响应执行默认操作?
采纳答案by Sean
You don't need jQuery at all. Just submit your POST via a form normally, and on the server side, add the HTTP header
你根本不需要 jQuery。只需通过表单正常提交您的POST,并在服务器端添加HTTP标头
Content-Disposition: attachment; filename="whatever.pdf"
The browser will do its default thing.
浏览器将执行其默认操作。
Alternately, if you want to be more careful about reporting any errors that might occur during the PDF generation, you can do this. POST your parameters to your server with jQuery. On the server, generate the binary content and cache it somewhere for a few minutes, accessible via a key that you put in the user's session, and return a "success" Ajax response to your page (or if there was an error, return an "error" response). If the page gets back a success response, it can immediately do something like:
或者,如果您想更加小心地报告 PDF 生成期间可能发生的任何错误,您可以这样做。使用 jQuery 将您的参数发布到您的服务器。在服务器上,生成二进制内容并将其缓存在某处几分钟,可通过您放入用户会话的密钥访问,并向您的页面返回一个“成功”的 Ajax 响应(或者如果出现错误,则返回一个“错误”响应)。如果页面返回成功响应,它可以立即执行以下操作:
window.location = "/get/my/pdf";
The server then returns the cached PDF content. Be sure to include the Content-Disposition header, as above.
然后服务器返回缓存的 PDF 内容。确保包含 Content-Disposition 标头,如上所述。
回答by Vinodh Ramasubramanian
Take a look at - jQuery Plugin for Requesting Ajax-like File Downloads
看一看 - jQuery Plugin for Requesting Ajax-like File Downloads
The whole plugin
is just about 30 lines of code (including comments).
整个plugin
代码大约只有 30 行(包括注释)。
The call is fairly similar to jquery ajax call.
该调用与 jquery ajax 调用非常相似。
$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );
Ofcourse, you have to set the content-type and Content-Disposition headers on the server side as you would for any such download.
当然,您必须像进行任何此类下载一样在服务器端设置 content-type 和 Content-Disposition 标头。
In java I would do something like this
在java中我会做这样的事情
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
回答by Mark Seefeldt
The answer mentioning "jQuery Plugin for Requesting Ajax-like File Downloads" got me headed down the right direction, but it didn't work entirely for my situation since I have a complex object and array of objects to pass in as my search criteria/filter data. I figured I'd share my code in case someone else runs into this situation too.
提到“用于请求类似 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');
It probably doesn't make much of a difference, but to provide some context, I've got a javascript and knockout UI calling into WebAPI, MVC4, and nHibernate. The 'format=csv' part of the query string triggers a MediaTypeFormatter to convert the returned models into a CSV file type. If I leave that off, then I get the models back from the API and can populate a Slick grid for display.
它可能没有太大区别,但为了提供一些上下文,我有一个 javascript 和敲除 UI 调用 WebAPI、MVC4 和 nHibernate。查询字符串的 'format=csv' 部分触发 MediaTypeFormatter 将返回的模型转换为 CSV 文件类型。如果我不这样做,那么我可以从 API 取回模型,并可以填充 Slick 网格以供显示。
回答by Anti-g
I had the same problem but on top use an RESTFUL webservice
for this and have an complex data object which i must post.
我有同样的问题,但最重要的RESTFUL webservice
是为此使用 an并且有一个我必须发布的复杂数据对象。
My solution:
like the jQuery Plugin i build a temp formular and submit it. But i send the data object as an parameter with json content (i use here AngularJS
but it should work with jQuery.param()
too.)
我的解决方案:像 jQuery 插件一样,我构建了一个临时公式并提交。但是我将数据对象作为带有 json 内容的参数发送(我在这里使用,AngularJS
但它也应该可以使用jQuery.param()
。)
Javascript:
Javascript:
$('<form target="_blank" action="' + appConstants.restbaseurl + '/print/pdf" method="POST">' +
"<input name='data' value='" + angular.toJson($scope.versicherung) + "' />" +
'</form>').appendTo('body').submit().remove();
on the server side we use a CXF REST Service
with an HymanSON
Provider:
在服务器端,我们使用一个CXF REST Service
与HymanSON
提供者:
Spring Config:
弹簧配置:
<jaxrs:server id="masterdataService" address="/">
<jaxrs:serviceBeans>
<ref bean="printRestServiceBean" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.Hymanson.jaxrs.HymansonJsonProvider" />
<bean class="de.controller.ExceptionHandler" />
</jaxrs:providers>
</jaxrs:server>
in the controller i extracted the param and converted it back to an Java Pojo:
在控制器中,我提取了参数并将其转换回 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.Hymanson.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;
}
}
in the PrintService i build the pdf binary and the response:
在 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();
}
This solution works for all browsers (even for IE9 which can't handle data url's) and on tablets and smartphone and it have no problems with popupblockers
此解决方案适用于所有浏览器(甚至适用于无法处理数据 url 的 IE9)以及平板电脑和智能手机,并且它对 popupblockers 没有问题
回答by MichaelK
The jQuery Plugin for Requesting Ajax-like File Downloads is - essentially - creating a form, adding the post data as hidden field(s), adding it to the body of the page, submitting it and removing it.
用于请求类似 Ajax 的文件下载的 jQuery 插件 - 本质上 - 创建一个表单,将发布数据添加为隐藏字段,将其添加到页面正文中,提交并删除它。
In my case I did not have a form, only a chunk of data to be posted as it was. That made for the following solution. On the server side I can get the data by simply reading the "data" parameter from the request and URI-decoding it.
就我而言,我没有表格,只有一大块数据要按原样发布。这导致了以下解决方案。在服务器端,我可以通过简单地从请求中读取“数据”参数并对其进行 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();
};
回答by Ustaman Sangat
I fail to understand why you want an ajax request to a file download url! But if it's more like client itself generates some content for download - use a data uri. Works perfectly for Chrome and Firefox 20+. Safari and IE NOT! If Flash is allowed, you could use downloadifier.
我不明白为什么你想要一个对文件下载 url 的 ajax 请求!但是,如果它更像是客户端本身生成一些供下载的内容 - 使用数据 uri。适用于 Chrome 和 Firefox 20+。Safari 和 IE 不是!如果允许使用 Flash,您可以使用下载程序。
Ah after reading your code, I see you want to send a bunch of parameters. Well unless the query string gets too long (IE8- has a limit of 2083) why not simply use an anchor with proper url?
啊看完你的代码,我看你要发送一堆参数。好吧,除非查询字符串太长(IE8- 有 2083 的限制)为什么不简单地使用带有正确 url 的锚点?
$('a.export-csv').click( function (evt){
linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
return true;
});
The above allows you to change the URL before the default event (the click) happens.
以上允许您在默认事件(点击)发生之前更改 URL。
回答by A Malik
I think the best will be to create a temp pdf file in the downloads folder and then load the file using pop-up having an iframe.. chrome will load it instantly but I suppose for other variants Acrobat reader must be installed to view the pdf but again you can use FlashPaper too :)
我认为最好的方法是在下载文件夹中创建一个临时的 pdf 文件,然后使用具有 iframe 的弹出窗口加载文件.. chrome 会立即加载它,但我想对于其他变体,必须安装 Acrobat 阅读器才能查看 pdf但是你也可以使用 FlashPaper :)