用JavaScript开始下载文件

时间:2008-12-13 21:37:04

标签: javascript ajax download

假设我有网站上文件的下载链接。

单击这些链接时,会向服务器发送一个AJAX请求,该请求返回带有文件位置的URL。

我想要做的是在响应回来时指示浏览器下载文件。有可行的方法吗?

12 个答案:

答案 0 :(得分:24)

我们这样做: 首先添加此脚本。

<script type="text/javascript">
function populateIframe(id,path) 
{
    var ifrm = document.getElementById(id);
    ifrm.src = "download.php?path="+path;
}
</script>

将它放在您想要下载按钮的位置(这里我们只使用链接):

<iframe id="frame1" style="display:none"></iframe>
<a href="javascript:populateIframe('frame1','<?php echo $path; ?>')">download</a>

文件'download.php'(需要放在你的服务器上)只包含:

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

因此,当您单击该链接时,隐藏的iframe将获取/打开源文件'download.php'。使用path作为get参数。 我们认为这是最好的解决方案!

应该注意的是,这个解决方案的PHP部分是一个简单的演示,可能非常非常不安全。它允许用户下载任何文件,而不仅仅是预定义的集合。这意味着他们可以下载网站本身的部分源代码,可能包含API凭证等。

答案 1 :(得分:18)

我创建了一个开源jQuery File Download pluginDemo with examples)(GitHub),这也可以帮助您解决问题。它与iframe非常相似,但有一些很酷的功能,我发现它非常方便:

  • 用户永远不会离开他们发起文件下载的同一页面。此功能对于现代Web应用程序变得至关重要
  • 经过测试的跨浏览器支持(包括移动设备!)
  • 它以类似于jQuery的AJAX API
  • 的方式支持POST和GET请求
  • successCallback和failCallback函数允许您明确用户在任一情况下看到的内容
  • 与jQuery UI一起,开发人员可以轻松地显示一个模式告诉用户文件下载正在发生,在下载开始后解除模式,甚至以友好的方式通知用户发生了错误。有关此示例,请参阅演示。

答案 2 :(得分:14)

阅读答案 - 包括接受的答案我想指出通过GET直接将路径传递给readfile的安全隐患。

对某些人来说似乎很明显,但有些人可能只是复制/粘贴此代码:

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

那么如果我将'/ path / to / fileWithSecrets'之类的内容传递给此脚本会发生什么? 给定的脚本将很乐意发送webserver用户可以访问的任何文件。

有关如何防止此问题的信息,请参阅此讨论:How do I make sure a file path is within a given subdirectory?

答案 3 :(得分:10)

如果这是您自己的服务器应用程序,那么我建议使用以下标题

Content-disposition: attachment; filename=fname.ext

这将强制任何浏览器下载文件,而不是在浏览器窗口中呈现它。

答案 4 :(得分:7)

只需从您的javascript调用window.location.href = new_url,它就会将浏览器重定向到该网址,因为用户已将其输入地址栏

答案 5 :(得分:3)

同意maxnk提到的方法,但是您可能需要重新考虑尝试自动强制浏览器下载URL。它可能适用于二进制文件,但对于其他类型的文件(文本,PDF,图像,视频),浏览器可能希望在窗口(或IFRAME)中呈现它而不是保存到磁盘。

如果你真的需要进行Ajax调用以获得最终的下载链接,那么使用DHTML动态地将下载链接(从ajax响应)写入页面呢?这样,用户可以点击它下载(如果是二进制)或在浏览器中查看 - 或者在链接上选择“另存为”以保存到磁盘。这是一个额外的点击,但用户有更多的控制权。

答案 6 :(得分:3)

试试这个lib https://github.com/PixelsCommander/Download-File-JS它比以前描述的所有解决方案都更现代,因为它使用“下载”属性和方法组合来带来最佳体验。

在此解释 - http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/

似乎是用JavaScript开始下载的理想代码。

答案 7 :(得分:3)

要解决最高投票答案中的安全漏洞,您可以将iframe src直接设置为您想要的文件(而不是中间的php文件),并在.htaccess文件中设置标头信息:

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

答案 8 :(得分:2)

我建议在页面上创建一个不可见的iframe,并将它的src设置为你从服务器收到的url - 下载将在没有页面重新加载的情况下开始。

或者您可以将当前document.location.href设置为收到的网址。但如果请求的文档实际上不存在,那么这可能会导致用户看到错误。

答案 9 :(得分:2)

关于最佳答案,我有可能解决安全风险。

<?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']);
         }
     }
?>

使用glob()函数(我在下载文件的路径中测试了下载文件)我能够制作一个快速的文件数组,这些文件是“允许的”#34;下载并检查传递的路径。这不仅可以确保被抓取的文件不是敏感的,而且还可以同时检查文件是否存在。

〜注意:Javascript / HTML~

HTML:

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

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

答案 10 :(得分:1)

我建议window.open()打开一个弹出窗口。如果是下载,则没有窗口,您将获得您的文件。如果有404或其他东西,用户将在新窗口中看到它(因此,他们的工作不会受到打扰,但他们仍然会收到错误消息)。

答案 11 :(得分:1)

当你需要的是将浏览器重定向到不同的window.location.href时,你为什么要制作服务器端?

以下代码解析?file = QueryString(taken from this question)并在1秒内将用户重定向到该地址(即使在Android浏览器上也适用于我):

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

如果您的项目中有jQuery,请务必删除那些window.onpopstate&amp; window.onload处理程序并在$(document).ready(function(){});

中执行所有操作