为什么没有办法使用Ajax请求下载文件?

问题描述 投票:46回答:5

在我们的应用程序中,我们需要实现以下场景:

  1. 从客户端发送请求
  2. 服务器处理请求并生成文件
  3. 服务器响应返回文件
  4. 客户端浏览器显示文件下载弹出对话框,并允许用户下载文件

我们的应用程序是基于ajax的应用程序,因此对我们而言,发送ajax请求(像使用jquery.ajax()函数一样)非常容易和方便。

但是在googilng之后,事实证明只有在使用非ajax POST请求时才可以下载文件(如this popular SO thread中所述)。因此,我们需要实现更丑陋,更复杂的解决方案,该解决方案要求使用嵌套的隐藏字段来构建form的HTML结构。

有人可以用简单的词来解释为什么不能使用ajax请求来下载文件吗?其背后的机制是什么?

javascript ajax post download
5个回答
59
投票

与AJAX无关。当然,您可以使用AJAX下载文件。但是,文件将保留在内存中,即您无法将文件保存到磁盘。这是因为JavaScript无法与磁盘交互。这将是一个严重的安全问题,并且在所有主流浏览器中都被阻止。


3
投票

这可以使用称为Blob的新HTML5功能来完成。在该功能之上,有一个库FileSaver.js可用作包装器。


1
投票

这是我两天前问过自己的问题。有一个使用ExtJS编写的客户端项目,服务器端实现在ASP.Net上。我必须将服务器端转换为Java。有一个功能可以下载XML文件,该文件是服务器在客户端发出Ajax请求后生成的。众所周知,在Ajax请求之后不可能仅将文件存储在内存中就下载文件。但是...在原始应用程序浏览器中会显示带有打开,保存和取消下载选项的常规对话框。 ASP.Net某种程度上改变了标准行为...我花了两天时间再次证明-无法按常规方式下载文件...唯一的例外是ASP.Net ...这是ASP.Net代码

public static void WriteFileToResponse(byte[] fileData, string fileName)
    {
        var response = HttpContext.Current.Response;

        var returnFilename = Path.GetFileName(fileName);
        var headerValue = String.Format("attachment; filename={0}", 
            HttpUtility.UrlPathEncode(
                String.IsNullOrEmpty(returnFilename) 
                    ? "attachment" : returnFilename));
        response.AddHeader("content-disposition", headerValue);
        response.ContentType = "application/octet-stream";
        response.AddHeader("Pragma", "public");

        var utf8 = Encoding.UTF8;
        response.Charset = utf8.HeaderName;
        response.ContentEncoding = utf8;
        response.Flush();
        response.BinaryWrite(fileData);
        response.Flush();
        response.Close();
    }

此方法从WebMethod调用,而该方法又从ExtJS.Ajax.request调用。那就是魔术。对我来说,我以servlet和隐藏的iframe结尾...


0
投票

对于那些希望使用更现代方法的人,可以使用fetch API。以下示例显示如何下载PDF文件。使用以下代码即可轻松完成。

fetch(url, {
    body: JSON.stringify(data),
    method: 'POST',
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    },
})
.then(response => response.blob())
.then(response => {
    const blob = new Blob([response], {type: 'application/pdf'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.pdf";
    document.body.appendChild(a);
    a.click();
})

我相信这种方法比其他XMLHttpRequest解决方案更容易理解。而且,它具有与jQuery方法类似的语法,而无需添加任何其他库。

当然,我建议您检查要开发的浏览器,因为这种新方法不适用于IE。您可以在以下[链接] [1]上找到完整的浏览器兼容性列表。

重要

:在本示例中,我向服务器侦听给定的url时发送JSON请求。必须设置此url,在我的示例中,我假设您知道这一部分。另外,请考虑您的请求正常工作所需的标题。由于我正在发送JSON,因此必须添加Content-Type标头并将其设置为application/json; charset=utf-8,以便让服务器知道它将接收的请求的类型。

-3
投票

您可以通过在下载页面中使用隐藏的iframe来执行此操作

© www.soinside.com 2019 - 2024. All rights reserved.