使用ajax请求下载文件

IT技术 javascript php ajax file download
2021-01-17 08:50:31

当我点击一个按钮时,我想发送一个“ajax下载请求”,所以我是这样尝试的:

javascript:

var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();

下载.php:

<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");    
readfile("file.txt");
?>

但没有按预期工作,我该怎么办?先感谢您

6个回答

2015 年 4 月 27 日更新

进入 HTML5 场景的是下载属性在 Firefox 和 Chrome 中得到支持,并且很快就会出现在 IE11 中。根据您的需要,您可以使用它代替 AJAX 请求(或使用window.location),只要您要下载的文件与您的站点位于同一来源。

您始终可以window.location通过使用一些 JavaScript来测试是否download支持AJAX 请求/回退,如果不支持,则将其切换为调用window.location.

原答案

您不能让 AJAX 请求打开下载提示,因为您必须实际导航到文件以提示下载。相反,您可以使用成功函数导航到 download.php。这将打开下载提示,但不会更改当前页面。

$.ajax({
    url: 'download.php',
    type: 'POST',
    success: function() {
        window.location = 'download.php';
    }
});

即使这回答了问题,最好还是完全使用window.location和避免 AJAX 请求。

它确实调用了两次页面,因此如果您在该页面中查询数据库,这意味着两次访问 DB。
2021-03-15 08:50:31
但它会发送请求 2 次,这是不正确的
2021-03-21 08:50:31
这不是两次调用链接吗?我在类似的船上......我在标题中传递了很多安全信息,并且能够在成功函数中解析文件对象,但不知道如何触发下载提示。
2021-03-28 08:50:31
让我解释一下这对我有什么帮助……这个例子本来可以更完整。使用“download.php?get_file=true”之类的...我有一个 ajax 函数,可以对表单提交进行一些错误检查,然后创建一个 csv 文件。如果错误检查失败,它必须返回失败的原因。如果它创建了 CSV,它会告诉父级“继续获取文件”。我通过使用表单变量发布到 ajax 文件,然后将不同的参数发布到同一个文件中,说“将您刚刚创建的文件交给我”(路径/名称被硬编码到 ajax 文件中)。
2021-03-28 08:50:31
@user1447679 查看替代解决方案:stackoverflow.com/questions/38665947/...
2021-04-05 08:50:31

要使浏览器下载文件,您需要发出这样的请求:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }
@Taha 我在 Edge 上测试了这个,它似乎有效。不知道IE虽然。我的客户不针对 IE 用户 ;-) 我幸运吗?:D
2021-03-19 08:50:31
这对我有用,但在 firefox 中,我需要先在 DOM 中放置一个 <a> 标签,并将其作为我的链接引用,而不是即时创建一个以便文件自动下载。
2021-03-24 08:50:31
谢谢@João,我很长时间以来一直在寻找这个解决方案。
2021-03-27 08:50:31
工作,但如果文件在执行期间创建会发生什么?它不像已经创建文件时那样工作。
2021-04-03 08:50:31
@ErikDonohoo您也可以<a>使用JS“即时”创建标签,但必须将其附加到document.body. 您当然想同时隐藏它。
2021-04-09 08:50:31

你实际上根本不需要ajax。如果您只是将“download.php”设置为按钮上的 href,或者,如果它不是链接,请使用:

window.location = 'download.php';

浏览器应该识别二进制下载,而不是加载实际页面,而只是将文件作为下载提供。

一直在寻找解决方案,这非常优雅和完美。非常感谢。
2021-03-21 08:50:31
你是对的@mikemaccana,我实际上是指 ajax :)。
2021-03-28 08:50:31
当然,这个解决方案只有在它是一个已经存在的静态文件时才有效。
2021-03-31 08:50:31
如果服务器以错误响应,但没有任何方法可以留在您的主页上而不会被浏览器重定向到错误页面。至少当 window.location 的结果返回 404 时,Chrome 是这样做的。
2021-04-03 08:50:31
您用来更改的编程语言window.location JavaScript。
2021-04-09 08:50:31

跨浏览器解决方案,在 Chrome、Firefox、Edge、IE11 上测试。

在 DOM 中,添加一个隐藏的链接标签:

<a id="target" style="display: none"></a>

然后:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";
req.setRequestHeader('my-custom-header', 'custom-value'); // adding some headers (if needed)

req.onload = function (event) {
  var blob = req.response;
  var fileName = null;
  var contentType = req.getResponseHeader("content-type");

  // IE/EDGE seems not returning some response header
  if (req.getResponseHeader("content-disposition")) {
    var contentDisposition = req.getResponseHeader("content-disposition");
    fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
  } else {
    fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
  }

  if (window.navigator.msSaveOrOpenBlob) {
    // Internet Explorer
    window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
  } else {
    var el = document.getElementById("target");
    el.href = window.URL.createObjectURL(blob);
    el.download = fileName;
    el.click();
  }
};
req.send();
好的通用代码。@leo 你能通过添加自定义标题来改进这段代码Authorization吗?
2021-03-17 08:50:31
谢谢@leo。它很有帮助。此外,您建议window.URL.revokeObjectURL(el.href);在之后添加el.click()什么?
2021-03-18 08:50:31
如果内容处置指定非 UTF8 文件名,则文件名将是错​​误的。
2021-03-31 08:50:31

有可能的。您可以从 ajax 函数内部开始下载,例如,在创建 .csv 文件之后。

我有一个 ajax 函数,可以将联系人数据库导出到 .csv 文件,在它完成后,它会自动启动 .csv 文件下载。所以,在我得到 responseText 并且一切正常之后,我像这样重定向浏览器:

window.location="download.php?filename=export.csv";

我的download.php文件如下所示:

<?php

    $file = $_GET['filename'];

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment; filename=".$file."");
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: binary/octet-stream");
    readfile($file);

?>

没有任何页面刷新,文件自动开始下载。

注意- 在以下浏览器中测试:

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11
@MickaelBergeronNéron 为什么?
2021-03-12 08:50:31
这在安全方面不是很危险吗?
2021-03-13 08:50:31
我会这么认为是因为任何人都可以调用 download.php?filename=[something] 并尝试一些路径和文件名,尤其是常见的,这甚至可以在程序或脚本的循环内完成。
2021-03-15 08:50:31
@PedroSousa .. 不。htaccess 通过 Apache 控制对文件结构的访问。由于访问已到达 PHP 脚本,htaccess 现在停止其职责。这是一个非常严重的安全漏洞,因为实际上,PHP(以及运行它的用户)可以读取任何文件,因此它可以传递到读取文件中......人们应该始终清理要读取的请求文件
2021-03-16 08:50:31
.htaccess 不会避免吗?
2021-03-29 08:50:31