POST 到服务器,接收 PDF,使用 jQuery 交付给用户
Posted
技术标签:
【中文标题】POST 到服务器,接收 PDF,使用 jQuery 交付给用户【英文标题】:POST to server, receive PDF, deliver to user w/ jQuery 【发布时间】:2011-01-12 07:04:34 【问题描述】:我有一个链接,用户单击该链接即可获取 PDF。在 jQuery 中,我创建了一个对服务器的 POST ajax 调用以获取 PDF。 PDF 带有正确的内容标题等,通常会导致浏览器打开 Reader 插件,或允许用户保存 PDF。
由于我正在获取带有 ajax 调用的 PDF,因此我不确定如何处理在 OnSuccess 回调中获得的数据。如何将收到的数据提供给浏览器并允许它使用 PDF 响应执行其默认操作?
【问题讨论】:
这将是浏览器通常对内容类型设置为 PDF 的响应所做的任何事情。打开阅读器,提示下载位置等。 【参考方案1】:看看-jQuery Plugin for Requesting Ajax-like File Downloads
整个plugin
大约只有 30 行代码(包括 cmets)。
该调用与 jquery ajax 调用非常相似。
$.download('/export.php','filename=myPDF&format=pdf&content=' + pdfData );
当然,您必须在服务器端设置 content-type 和 Content-Disposition 标头,就像任何此类下载一样。
在java中我会做这样的事情
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename="exported.pdf");
【讨论】:
这是答案,但我没有足够的声誉来投票。我知道我以错误的方式思考问题。【参考方案2】:你根本不需要 jQuery。只需通过表单正常提交您的 POST,然后在服务器端添加 HTTP 标头
Content-Disposition: attachment; filename="whatever.pdf"
浏览器会做它默认的事情。
或者,如果您想更加小心地报告在 PDF 生成期间可能发生的任何错误,您可以这样做。使用 jQuery 将您的参数发布到您的服务器。在服务器上,生成二进制内容并将其缓存在某处几分钟,可通过您放入用户会话中的密钥访问,并向您的页面返回“成功”Ajax 响应(或者如果出现错误,则返回“错误”响应)。如果页面返回成功响应,它可以立即执行以下操作:
window.location = "/get/my/pdf";
然后服务器返回缓存的 PDF 内容。请务必包含 Content-Disposition 标头,如上所述。
【讨论】:
你可能不需要,但有时你需要;)【参考方案3】:提到“用于请求类似 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 和淘汰 UI 调用到 WebAPI、MVC4 和 nHibernate。查询字符串的 'format=csv' 部分触发 MediaTypeFormatter 将返回的模型转换为 CSV 文件类型。如果我不这样做,那么我会从 API 中获取模型,并可以填充 Slick 网格以进行显示。
【讨论】:
【参考方案4】:我遇到了同样的问题,但最重要的是使用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 Service
和 JACKSON
提供者:
弹簧配置:
<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();
此解决方案适用于所有浏览器(甚至适用于无法处理数据 url 的 IE9)以及平板电脑和智能手机,并且弹出阻止程序没有问题
【讨论】:
你无法告诉用户下载已经完成,对吧? 不,除非您使用一些额外的技巧,例如设置cookies【参考方案5】:用于请求类似 Ajax 的文件下载的 jQuery 插件本质上是创建一个表单,将发布数据添加为隐藏字段,将其添加到页面主体,提交并删除它。
在我的情况下,我没有表格,只有一块数据要按原样发布。这导致了以下解决方案。在服务器端,我可以通过简单地从请求中读取“数据”参数并对其进行 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】:我不明白您为什么要对文件下载 url 发出 ajax 请求!但是,如果它更像是客户端本身生成一些供下载的内容 - 使用数据 uri。适用于 Chrome 和 Firefox 20+。 Safari 和 IE 不是!如果允许 Flash,您可以使用下载器。
啊,看了你的代码,我看到你想发送一堆参数。好吧,除非查询字符串太长(IE8- 限制为 2083),否则为什么不简单地使用具有正确 url 的锚点呢?
$('a.export-csv').click( function (evt)
linkEl.attr('href','/export?' + encodeURIComponent(formQueryString()));
return true;
);
以上允许您在默认事件(点击)发生之前更改 URL。
【讨论】:
啊,看了你的代码,我看到你要发送一堆参数。好吧,除非查询字符串太长(IE8- 限制为 2083),否则为什么不简单地使用具有正确 url 的锚点? 您的代码看起来不错,我尝试了类似的方法,它似乎可以工作。你能概括一下哪一部分不适合你吗?【参考方案7】:我认为最好的办法是在下载文件夹中创建一个临时 pdf 文件,然后使用具有 iframe 的弹出窗口加载该文件.. chrome 会立即加载它,但我想对于其他变体 Acrobat 阅读器必须安装到查看 pdf,但您也可以使用 FlashPaper :)
【讨论】:
答案与问题的上下文相去甚远,根本没有提供任何细节以上是关于POST 到服务器,接收 PDF,使用 jQuery 交付给用户的主要内容,如果未能解决你的问题,请参考以下文章
当使用 okhttp 发送 post 请求时,服务器接收到的请求正文为空。可能是啥问题?