使用ajax请求下载文件

dwthyt8l  于 2021-07-12  发布在  Java
关注(0)|答案(12)|浏览(284)

当我点击一个按钮时,我想发送一个“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");
?>

但效果不尽如人意,我该怎么办?先谢谢你

q7solyqu

q7solyqu1#

2015年4月27日更新
html5场景中出现的是下载属性。firefox和chrome都支持它,ie11也支持它。根据您的需要,您可以使用它来代替ajax请求(或者使用 window.location )只要您要下载的文件与您的站点位于同一来源。
您可以随时发出ajax请求/ window.location 使用javascript测试 download 如果不支持,则将其切换为呼叫 window.location .
原始答案
您不能让ajax请求打开下载提示符,因为您实际上必须导航到该文件以提示下载。相反,您可以使用success函数导航到download.php。这将打开下载提示,但不会更改当前页面。

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

尽管这回答了问题,但最好还是用 window.location 完全避免ajax请求。

gwo2fgha

gwo2fgha2#

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

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

snz8szmq3#

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

window.location = 'download.php';

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

yiytaume

yiytaume4#

跨浏览器解决方案,在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();
inkz8wg9

inkz8wg95#

这是可能的。您可以从ajax函数内部开始下载,例如,就在.csv文件创建之后。
我有一个ajax函数,它可以将联系人数据库导出到一个.csv文件,完成后,它会自动开始下载.csv文件。所以,当我得到响应文本并且一切正常后,我重定向浏览器如下:

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
6kkfgxo0

6kkfgxo06#

我更喜欢 location.assign(url); 完整语法示例:

document.location.assign('https://www.urltodocument.com/document.pdf');

developer.mozilla.org/en-us/docs/web/api/location.assign

4sup72z8

4sup72z87#

从文件头解码文件名有点复杂。。。

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, '');
    }
66bbxpm5

66bbxpm58#

这个解决方案和上面的没什么不同,但对我来说效果很好,而且我觉得很干净。
我建议对文件服务器端进行base64编码(base64\u encode(),如果您使用的是php),并将base64编码的数据发送到客户端
在客户机上执行以下操作:

let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file);
 let uri = URL.createObjectURL(blob);
 let link = document.createElement("a");
 link.download = THE_FILE_NAME,
 link.href = uri;
 document.body.appendChild(link);
 link.click();
 document.body.removeChild(link);

这段代码将编码的数据放在一个链接中,模拟单击链接,然后将其删除。

ozxc1zmp

ozxc1zmp9#

你的需求由 window.location('download.php'); 但是我认为您需要传递要下载的文件,而不是总是下载同一个文件,这就是为什么您要使用请求,一个选项是创建一个像showfile.php这样简单的php文件并执行如下请求

var myfile = filetodownload.txt
var url = "shofile.php?file=" + myfile ;
ajaxRequest.open("GET", url, true);

显示文件.php

<?php
$file = $_GET["file"] 
echo $file;

其中file是在请求中通过get或post传递的文件名,然后简单地在函数中捕获响应

if(ajaxRequest.readyState == 4){
                        var file = ajaxRequest.responseText;
                        window.location = 'downfile.php?file=' + file;  
                    }
                }
at0kjp5o

at0kjp5o10#

还有另一种解决方案可以在ajax中下载web页面。但我指的是一个网页,必须首先处理,然后下载。
首先,您需要将页面处理与结果下载分开。
1) 在ajax调用中只进行页面计算。

$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },

       function(data, status) 
       {
            if (status == "success") 
            {
                /* 2) In the answer the page that uses the previous calculations is downloaded. For example, this can be a page that prints the results of a table calculated in the ajax call. */
                window.location.href = DownloadPage.php+"?ID="+29;
            }               
       }
);

// For example: in the CalculusPage.php

    if ( !empty($_POST["calculusFunction"]) ) 
    {
        $ID = $_POST["ID"];

        $query = "INSERT INTO ExamplePage (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
        ...
    }

// For example: in the DownloadPage.php

    $ID = $_GET["ID"];

    $sede = "SELECT * FROM ExamplePage WHERE id = ".$ID;
    ...

    $filename="Export_Data.xls";
    header("Content-Type: application/vnd.ms-excel");
    header("Content-Disposition: inline; filename=$filename");

    ...

我希望这个解决方案能像对我一样对许多人有用。

iaqfqrcu

iaqfqrcu11#

对于那些寻求更现代方法的人,可以使用 fetch API . 下面的示例演示如何下载电子表格文件。使用以下代码很容易完成。

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/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.xlsx";
    document.body.appendChild(a);
    a.click();
})

我相信这种方法比其他方法更容易理解 XMLHttpRequest 解决。而且,它的语法与 jQuery 方法,而无需添加任何其他库。
当然,我建议您检查一下您正在开发的浏览器,因为这种新方法不适用于ie。您可以在下面的链接中找到完整的浏览器兼容性列表。
重要提示:在这个示例中,我向侦听给定 url . 这个 url 必须设定,以我为例,我假设你知道这一部分。另外,请考虑您的请求工作所需的标头。因为我要发送一个json,所以必须添加 Content-Type 标题并将其设置为 application/json; charset=utf-8 ,以便让服务器知道它将接收的请求类型。

uqdfh47h

uqdfh47h12#

@joao-marcos的解决方案适合我,但我必须修改代码,使其在ie上工作,如果下面的代码看起来像什么

downloadFile(url,filename) {
        var that = this;
        const extension =  url.split('/').pop().split('?')[0].split('.').pop();

        var req = new XMLHttpRequest();
        req.open("GET", url, true);
        req.responseType = "blob";
        req.onload = function (event) {
            const fileName = `${filename}.${extension}`;
            const blob = req.response;

            if (window.navigator.msSaveBlob) { // IE
                window.navigator.msSaveOrOpenBlob(blob, fileName);
            } 
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);                
            link.download = fileName;
            link.click();
            URL.revokeObjectURL(link.href);

        };

        req.send();
    },

相关问题