使用ajax请求下载文件

时间:2020-12-21 09:45:43

I want to send an "ajax download request" when I click on a button, so I tried in this way:

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

javascript:

javascript:

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

download.php:

download.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");
?>

but doesn't work as expected, how can I do ? Thank you in advance

但不像预期的那样工作,我该怎么办?提前谢谢你

7 个解决方案

#1


86  

Update April 27, 2015

2015年4月27日更新

Up and coming to the HTML5 scene is the download attribute. It's supported in Firefox and Chrome, and soon to come to IE11. Depending on your needs, you could use it instead of an AJAX request (or using window.location) so long as the file you want to download is on the same origin as your site.

HTML5场景中的下载属性。它在Firefox和Chrome中得到支持,很快就会出现在IE11中。根据您的需要,您可以使用它而不是AJAX请求(或使用windows .location),只要您想下载的文件与您的站点的源文件相同。

You could always make the AJAX request/window.location a fallback by using some JavaScript to test if download is supported and if not, switching it to call window.location.

您总是可以发出AJAX请求/窗口。通过使用一些JavaScript来测试是否支持下载,如果不支持,则切换到调用windows .location。

Original answer

原来的答案

You can't have an AJAX request open the download prompt since you physically have to navigate to the file to prompt for download. Instead, you could use a success function to navigate to download.php. This will open the download prompt but won't change the current page.

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

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

Even though this answers the question, it's better to just use window.location and avoid the AJAX request entirely.

尽管这回答了问题,但最好还是使用窗口。定位并完全避免AJAX请求。

#2


36  

You actually don't need ajax at all for this. If you just set "download.php" as the href on the button, or, if it's not a link use:

实际上,这根本不需要ajax。如果你设置为“下载”。php“作为href按钮,或者,如果不是链接使用:

window.location = 'download.php';

The browser should recognise the binary download and not load the actual page but just serve the file as a download.

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

#3


13  

It is possible. You can have the download started from inside an ajax function, for example, just after the .csv file is created.

这是可能的。您可以在ajax函数中启动下载,例如,在.csv文件创建之后。

I have an ajax function that exports a database of contacts to a .csv file, and just after it finishes, it automatically starts the .csv file download. So, after I get the responseText and everything is Ok, I redirect browser like this:

我有一个ajax函数,它将联系人数据库导出到.csv文件中,并在完成后自动启动.csv文件下载。当我收到responseText,一切正常后,我重定向浏览器如下:

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

My download.php file looks like this:

我的下载。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);

?>

There is no page refresh whatsoever and the file automatically starts downloading.

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

NOTE - Tested in the following browsers:

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

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11

#4


12  

To make the browser downloads a file you need to make the request like that:

要让浏览器下载文件,你需要这样做:

 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();
 }

#5


2  

Cross browser solution, tested on Chrome, Firefox, Edge, IE11.

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

In the DOM, add an hidden link tag:

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

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

Then:

然后:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";

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();

#6


1  

I prefer Location.assign()

我更喜欢Location.assign()

developer.mozilla.org/en-US/docs/Web/API/Location.assign

developer.mozilla.org/en-US/docs/Web/API/Location.assign

#7


0  

Decoding a filename from the header is a little bit more complex...

从标题中解码文件名有点复杂……

    var filename = "default.pdf";
    var disposition = req.getResponseHeader('Content-Disposition');

    if (disposition && disposition.indexOf('attachment') !== -1) 
    {
       var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
       var matches = filenameRegex.exec(disposition);

       if (matches != null && matches[1]) 
           filename = matches[1].replace(/['"]/g, '');
    }

#1


86  

Update April 27, 2015

2015年4月27日更新

Up and coming to the HTML5 scene is the download attribute. It's supported in Firefox and Chrome, and soon to come to IE11. Depending on your needs, you could use it instead of an AJAX request (or using window.location) so long as the file you want to download is on the same origin as your site.

HTML5场景中的下载属性。它在Firefox和Chrome中得到支持,很快就会出现在IE11中。根据您的需要,您可以使用它而不是AJAX请求(或使用windows .location),只要您想下载的文件与您的站点的源文件相同。

You could always make the AJAX request/window.location a fallback by using some JavaScript to test if download is supported and if not, switching it to call window.location.

您总是可以发出AJAX请求/窗口。通过使用一些JavaScript来测试是否支持下载,如果不支持,则切换到调用windows .location。

Original answer

原来的答案

You can't have an AJAX request open the download prompt since you physically have to navigate to the file to prompt for download. Instead, you could use a success function to navigate to download.php. This will open the download prompt but won't change the current page.

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

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

Even though this answers the question, it's better to just use window.location and avoid the AJAX request entirely.

尽管这回答了问题,但最好还是使用窗口。定位并完全避免AJAX请求。

#2


36  

You actually don't need ajax at all for this. If you just set "download.php" as the href on the button, or, if it's not a link use:

实际上,这根本不需要ajax。如果你设置为“下载”。php“作为href按钮,或者,如果不是链接使用:

window.location = 'download.php';

The browser should recognise the binary download and not load the actual page but just serve the file as a download.

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

#3


13  

It is possible. You can have the download started from inside an ajax function, for example, just after the .csv file is created.

这是可能的。您可以在ajax函数中启动下载,例如,在.csv文件创建之后。

I have an ajax function that exports a database of contacts to a .csv file, and just after it finishes, it automatically starts the .csv file download. So, after I get the responseText and everything is Ok, I redirect browser like this:

我有一个ajax函数,它将联系人数据库导出到.csv文件中,并在完成后自动启动.csv文件下载。当我收到responseText,一切正常后,我重定向浏览器如下:

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

My download.php file looks like this:

我的下载。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);

?>

There is no page refresh whatsoever and the file automatically starts downloading.

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

NOTE - Tested in the following browsers:

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

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11

#4


12  

To make the browser downloads a file you need to make the request like that:

要让浏览器下载文件,你需要这样做:

 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();
 }

#5


2  

Cross browser solution, tested on Chrome, Firefox, Edge, IE11.

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

In the DOM, add an hidden link tag:

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

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

Then:

然后:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";

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();

#6


1  

I prefer Location.assign()

我更喜欢Location.assign()

developer.mozilla.org/en-US/docs/Web/API/Location.assign

developer.mozilla.org/en-US/docs/Web/API/Location.assign

#7


0  

Decoding a filename from the header is a little bit more complex...

从标题中解码文件名有点复杂……

    var filename = "default.pdf";
    var disposition = req.getResponseHeader('Content-Disposition');

    if (disposition && disposition.indexOf('attachment') !== -1) 
    {
       var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
       var matches = filenameRegex.exec(disposition);

       if (matches != null && matches[1]) 
           filename = matches[1].replace(/['"]/g, '');
    }