Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
253 views
in Technique[技术] by (71.8m points)

javascript - JavaScript / jQuery通过JSON数据通过POST下载文件(JavaScript/jQuery to download file via POST with JSON data)

I have a jquery-based single-page webapp.

(我有一个基于jquery的单页webapp。)

It communicates with a RESTful web service via AJAX calls.

(它通过AJAX调用与RESTful Web服务进行通信。)

I'm trying to accomplish the following:

(我正在尝试完成以下任务:)

  1. Submit a POST that contains JSON data to a REST url.

    (将包含JSON数据的POST提交到REST URL。)

  2. If the request specifies a JSON response, then JSON is returned.

    (如果请求指定JSON响应,则返回JSON。)

  3. If the request specifies a PDF/XLS/etc response, then a downloadable binary is returned.

    (如果请求指定PDF / XLS / etc响应,则返回可下载的二进制文件。)

I have 1 & 2 working now, and the client jquery app displays the returned data in the web page by creating DOM elements based on the JSON data.

(我现在有1&2,并且客户端jquery应用通过基于JSON数据创建DOM元素来在网页中显示返回的数据。)

I also have #3 working from the web-service point of view, meaning it will create and return a binary file if given the correct JSON parameters.

(从Web服务的角度来看,我也有#3的工作,这意味着如果给出正确的JSON参数,它将创建并返回一个二进制文件。)

But I'm unsure the best way to deal with #3 in the client javascript code.

(但是我不确定在客户端JavaScript代码中处理#3的最佳方法。)

Is it possible to get a downloadable file back from an ajax call like this?

(是否可以通过这样的ajax调用取回可下载文件?)

How do I get the browser to download and save the file?

(如何让浏览器下载并保存文件?)

$.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;
    }
});

The server responds with the following headers:

(服务器使用以下标头进行响应:)

Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)

Another idea is to generate the PDF and store it on the server and return JSON that includes a URL to the file.

(另一个想法是生成PDF并将其存储在服务器上,并返回包含文件URL的JSON。)

Then, issue another call in the ajax success handler to do something like the following:

(然后,在ajax成功处理程序中发出另一个调用,以执行以下操作:)

success: function(json,status) {
    window.location.href = json.url;
}

But doing that means I would need to make more than one call to the server, and my server would need to build downloadable files, store them somewhere, then periodically clean up that storage area.

(但这意味着我需要对服务器进行多次调用,并且服务器需要构建可下载文件,将它们存储在某个地方,然后定期清理该存储区域。)

There must be a simpler way to accomplish this.

(必须有一种更简单的方法来完成此任务。)

Ideas?

(有想法吗?)


EDIT: After reviewing the docs for $.ajax, I see that the response dataType can only be one of xml, html, script, json, jsonp, text , so I'm guessing there is no way to directly download a file using an ajax request, unless I embed the binary file in using Data URI scheme as suggested in the @VinayC answer (which is not something I want to do).

(编辑:审查$ .ajax的文档后,我看到响应数据类型只能是xml, html, script, json, jsonp, text ,因此我猜测没有办法直接使用ajax请求,除非我按照@VinayC答案中的建议使用Data URI方案嵌入二进制文件(这不是我想要做的)。)

So I guess my options are:

(所以我想我的选择是:)

  1. Not use ajax and instead submit a form post and embed my JSON data into the form values.

    (不使用ajax,而是提交一个表单发布,并将我的JSON数据嵌入到表单值中。)

    Would probably need to mess with hidden iframes and such.

    (可能需要弄乱隐藏的iframe等。)

  2. Not use ajax and instead convert my JSON data into a query string to build a standard GET request and set window.location.href to this URL.

    (不使用ajax,而是将我的JSON数据转换为查询字符串以构建标准的GET请求,并将window.location.href设置为此URL。)

    May need to use event.preventDefault() in my click handler to keep browser from changing from the application URL.

    (可能需要在我的点击处理程序中使用event.preventDefault(),以防止浏览器从应用程序URL更改。)

  3. Use my other idea above, but enhanced with suggestions from the @naikus answer.

    (使用我上面的其他想法,但是在@naikus答案中的建议得到了增强。)

    Submit AJAX request with some parameter that lets web-service know this is being called via an ajax call.

    (提交带有一些参数的AJAX请求,该参数使Web服务知道通过ajax调用正在调用该参数。)

    If the web service is called from an ajax call, simply return JSON with a URL to the generated resource.

    (如果从ajax调用中调用了Web服务,则只需将带有URL的JSON返回到生成的资源即可。)

    If the resource is called directly, then return the actual binary file.

    (如果直接调用资源,则返回实际的二进制文件。)

The more I think about it, the more I like the last option.

(我想得越多,我越喜欢最后一个选择。)

This way I can get information back about the request (time to generate, size of file, error messages, etc.) and I can act on that information before starting the download.

(这样,我可以获取有关请求的信息(生成时间,文件大小,错误消息等),并且可以在开始下载之前根据该信息进行操作。)

The downside is extra file management on the server.

(缺点是服务器上的额外文件管理。)

Any other ways to accomplish this?

(还有其他方法可以做到这一点吗?)

Any pros/cons to these methods I should be aware of?

(我应该注意这些方法的利弊吗?)

  ask by Tauren translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

letronje 's solution only works for very simple pages.

(letronje的解决方案仅适用于非常简单的页面。)

document.body.innerHTML += takes the HTML text of the body, appends the iframe HTML, and sets the innerHTML of the page to that string.

(document.body.innerHTML +=接收正文的HTML文本,附加iframe HTML,并将页面的innerHTML设置为该字符串。)

This will wipe out any event bindings your page has, amongst other things.

(这将抹除您的页面具有的所有事件绑定。)

Create an element and use appendChild instead.

(创建一个元素,并改用appendChild 。)

$.post('/create_binary_file.php', postData, function(retData) {
  var iframe = document.createElement("iframe");
  iframe.setAttribute("src", retData.url);
  iframe.setAttribute("style", "display: none");
  document.body.appendChild(iframe);
}); 

Or using jQuery

(或使用jQuery)

$.post('/create_binary_file.php', postData, function(retData) {
  $("body").append("<iframe src='" + retData.url+ "' style='display: none;' ></iframe>");
}); 

What this actually does: perform a post to /create_binary_file.php with the data in the variable postData;

(这实际上是做什么的:使用变量postData中的数据执行到/create_binary_file.php的发布;)

if that post completes successfully, add a new iframe to the body of the page.

(如果该帖子成功完成,则在页面正文中添加一个新的iframe。)

The assumption is that the response from /create_binary_file.php will include a value 'url', which is the URL that the generated PDF/XLS/etc file can be downloaded from.

(假定来自/create_binary_file.php的响应将包含值'url',这是可从中下载生成的PDF / XLS / etc文件的URL。)

Adding an iframe to the page that references that URL will result in the browser promoting the user to download the file, assuming that the web server has the appropriate mime type configuration.

(假设Web服务器具有适当的mime类型配置,则将iframe添加到引用该URL的页面将导致浏览器提示用户下载文件。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...