starting file download with JavaScript

2020-01-23 17:14发布

Let's say I have download links for files on my site.

When clicked these links send an AJAX request to the server which returns the URL with the location of the file.

What I want to do is direct the browser to download the file when the response gets back. Is there a portable way to do this?

12条回答
ゆ 、 Hurt°
2楼-- · 2020-01-23 17:22

Why are you making server side stuff when all you need is to redirect browser to different window.location.href?

Here is code that parses ?file= QueryString (taken from this question) and redirects user to that address in 1 second (works for me even on Android browsers):

<script type="text/javascript">
    var urlParams;
    (window.onpopstate = function () {
        var match,
        pl = /\+/g,  // Regex for replacing addition symbol with a space
        search = /([^&=]+)=?([^&]*)/g,
        decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
        query = window.location.search.substring(1);

        urlParams = {};
        while (match = search.exec(query))
            urlParams[decode(match[1])] = decode(match[2]);
    })();

    (window.onload = function() {
        var path = urlParams["file"];
        setTimeout(function() { document.location.href = path; }, 1000);
    });
</script>

If you have jQuery in your project definitely remove those window.onpopstate & window.onload handlers and do everything in $(document).ready(function () { } );

查看更多
Emotional °昔
3楼-- · 2020-01-23 17:30

To get around the security flaw in the top-voted answer, you can set the iframe src directly to the file you want (instead of an intermediate php file) and set the header information in an .htaccess file:

<Files *.apk>
     ForceType application/force-download
     Header set Content-Disposition attachment
     Header set Content-Type application/vnd.android.package-archive
     Header set Content-Transfer-Encoding binary
</Files>
查看更多
小情绪 Triste *
4楼-- · 2020-01-23 17:35

In relation to the top answer I have a possible solution to the security risk.

<?php
     if(isset($_GET['path'])){
         if(in_array($_GET['path'], glob("*/*.*"))){
             header("Content-Type: application/octet-stream");
             header("Content-Disposition: attachment; filename=".$_GET['path']);
             readfile($_GET['path']);
         }
     }
?>

Using the glob() function (I tested the download file in a path one folder up from the file to be downloaded) I was able to make a quick array of files that are "allowed" to be downloaded and checked the passed path against it. Not only does this insure that the file being grabbed isn't something sensitive but also checks on the files existence at the same time.

~Note: Javascript / HTML~

HTML:

<iframe id="download" style="display:none"></iframe>

and

<input type="submit" value="Download" onclick="ChangeSource('document_path');return false;">

JavaScript:

<script type="text/javascript">
    <!--
        function ChangeSource(path){
            document.getElementByID('download').src = 'path_to_php?path=' + document_path;
        }
    -->
</script>
查看更多
迷人小祖宗
5楼-- · 2020-01-23 17:36

I'd suggest window.open() to open a popup window. If it's a download, there will be no window and you will get your file. If there is a 404 or something, the user will see it in a new window (hence, their work will not be bothered, but they will still get an error message).

查看更多
不美不萌又怎样
6楼-- · 2020-01-23 17:37

If this is your own server application then i suggest using the following header

Content-disposition: attachment; filename=fname.ext

This will force any browser to download the file and not render it in the browser window.

查看更多
Bombasti
7楼-- · 2020-01-23 17:41

Reading the answers - including the accepted one I'd like to point out the security implications of passing a path directly to readfile via GET.

It may seem obvious to some but some may simply copy/paste this code:

<?php 
   header("Content-Type: application/octet-stream");
   header("Content-Disposition: attachment; filename=".$_GET['path']);
   readfile($_GET['path']);
?>

So what happens if I pass something like '/path/to/fileWithSecrets' to this script? The given script will happily send any file the webserver-user has access to.

Please refer to this discussion for information how to prevent this: How do I make sure a file path is within a given subdirectory?

查看更多
登录 后发表回答