我有一个基于 jquery 的单页 web 应用程序。它通过 AJAX 调用与 RESTful Web 服务进行通信。
我正在尝试完成以下工作:
- 将包含 JSON 数据的 POST 提交到 REST url。
- 如果请求指定 JSON 响应,则返回 JSON。
- 如果请求指定 PDF/XLS/etc 响应,则返回可下载的二进制文件。
我现在有 1 和 2 工作,客户端 jquery 应用程序通过基于 JSON 数据创建 DOM 元素在网页中显示返回的数据。从 Web 服务的角度来看,我还有 #3 工作,这意味着如果给定正确的 JSON 参数,它将创建并返回一个二进制文件。但我不确定在客户端 javascript 代码中处理 #3 的最佳方法。
是否有可能从这样的 ajax 调用中获取可下载的文件?如何让浏览器下载并保存文件?
$.ajax({
type: "POST",
url: "/services/test",
contentType: "application/json",
data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
dataType: "json",
success: function(json, status){
if (status != "success") {
log("Error loading data");
return;
}
log("Data loaded!");
},
error: function(result, status, err) {
log("Error loading data");
return;
}
});
服务器使用以下标头进行响应:
Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)
另一个想法是生成 PDF 并将其存储在服务器上,然后返回包含文件 URL 的 JSON。然后,在 ajax 成功处理程序中发出另一个调用以执行如下操作:
success: function(json,status) {
window.location.href = json.url;
}
但是这样做意味着我需要多次调用服务器,并且我的服务器需要构建可下载的文件,将它们存储在某处,然后定期清理该存储区域。
必须有一种更简单的方法来实现这一点。想法?
编辑:在查看 $.ajax 的文档后,我看到响应 dataType 只能是其中之一xml, html, script, json, jsonp, text
,所以我猜没有办法使用 ajax 请求直接下载文件,除非我嵌入二进制文件使用@VinayC 答案中建议的数据 URI 方案(这不是我想做的事情)。
所以我想我的选择是:
不使用 ajax,而是提交表单帖子并将我的 JSON 数据嵌入到表单值中。可能需要弄乱隐藏的 iframe 等。
不使用 ajax,而是将我的 JSON 数据转换为查询字符串以构建标准 GET 请求并将 window.location.href 设置为此 URL。可能需要在我的点击处理程序中使用 event.preventDefault() 来防止浏览器从应用程序 URL 发生变化。
使用我上面的其他想法,但通过@naikus 答案中的建议进行了增强。使用一些参数提交 AJAX 请求,让 Web 服务知道这是通过 ajax 调用调用的。如果 Web 服务是从 ajax 调用中调用的,只需将带有 URL 的 JSON 返回到生成的资源。如果直接调用资源,则返回实际的二进制文件。
我想得越多,我就越喜欢最后一个选项。通过这种方式,我可以获取有关请求的信息(生成时间、文件大小、错误消息等),并且可以在开始下载之前根据该信息采取行动。缺点是服务器上的额外文件管理。
还有其他方法可以实现吗?我应该注意这些方法的任何优点/缺点?