douhuan1950
douhuan1950
2013-12-29 21:35
浏览 220

使用ajax请求下载文件

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

javascript:

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

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

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

10条回答 默认 最新

  • douya6229
    douya6229 2013-12-29 21:39
    已采纳

    Update April 27, 2015

    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.

    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.

    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({
        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.

    点赞 评论
  • doutang1884
    doutang1884 2013-12-29 21:46

    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:

    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.

    点赞 评论
  • donv29560
    donv29560 2014-09-16 10:53

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

    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:

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

    My download.php file looks like this:

    <?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
    
    点赞 评论
  • duanjiao4763
    duanjiao4763 2015-01-13 10:11

    I prefer location.assign(url);

    Complete syntax example:

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

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

    点赞 评论
  • dqcuq4138
    dqcuq4138 2017-03-15 16:49

    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();
     }
    
    点赞 评论
  • douyalin2258
    douyalin2258 2017-03-20 23:28

    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[^;=
    ]*=((['"]).*?\2|[^;
    ]*)/;
           var matches = filenameRegex.exec(disposition);
    
           if (matches != null && matches[1]) 
               filename = matches[1].replace(/['"]/g, '');
        }
    
    点赞 评论
  • dongqin5604
    dongqin5604 2018-04-05 14:05

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

    In the DOM, add an hidden link tag:

    <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();
    
    点赞 评论
  • dongpi0658
    dongpi0658 2018-12-03 12:33

    This solution is not very different from those above, but for me it works very well and i think it's clean.

    I suggest to base64 encode the file server side (base64_encode(), if you are using PHP) and send the base64 encoded data to the client

    On the client you do this:

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

    This code puts the encoded data in a link and simulates a click on the link, then it removes it.

    点赞 评论
  • dongshou1856
    dongshou1856 2019-04-12 15:58

    Your needs are covered by window.location('download.php');
    But I think that you need to pass the file to be downloaded, not always download the same file, and that's why you are using a request, one option is to create a php file as simple as showfile.php and do a request like

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

    showfile.php

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

    where file is the file name passed via Get or Post in the request and then catch the response in a function simply

    if(ajaxRequest.readyState == 4){
                            var file = ajaxRequest.responseText;
                            window.location = 'downfile.php?file=' + file;  
                        }
                    }
    
    点赞 评论
  • duancunsu9209
    duancunsu9209 2019-05-21 15:21

    there is another solution to download a web page in ajax. But I am referring to a page that must first be processed and then downloaded.

    First you need to separate the page processing from the results download.

    1) Only the page calculations are made in the ajax call.

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

    I hope this solution can be useful for many, as it was for me.

    点赞 评论

相关推荐