douhuan1950
douhuan1950
2013-12-29 21:35

使用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 8年前

    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.

    点赞 评论 复制链接分享
  • douyalin2258 douyalin2258 4年前

    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, '');
        }
    
    点赞 评论 复制链接分享
  • donv29560 donv29560 7年前

    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
    
    点赞 评论 复制链接分享
  • dongpi0658 dongpi0658 3年前

    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.

    点赞 评论 复制链接分享
  • doutang1884 doutang1884 8年前

    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.

    点赞 评论 复制链接分享
  • dongshou1856 dongshou1856 2年前

    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;  
                        }
                    }
    
    点赞 评论 复制链接分享
  • duanjiao4763 duanjiao4763 6年前

    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

    点赞 评论 复制链接分享
  • duancunsu9209 duancunsu9209 2年前

    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.

    点赞 评论 复制链接分享
  • dqcuq4138 dqcuq4138 4年前

    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();
     }
    
    点赞 评论 复制链接分享
  • dongqin5604 dongqin5604 3年前

    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();
    
    点赞 评论 复制链接分享

相关推荐