60

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

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

我想要做的是在响应返回时指示浏览器下载文件。有没有便携的方法来做到这一点?

4

12 回答 12

26

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

<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”。使用路径作为获取参数。我们认为这是最好的解决方案!

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

于 2011-01-10T12:45:00.223 回答
18

我创建了一个开源jQuery 文件下载插件带有示例的演示)(GitHub),它也可以帮助您解决问题。它与 iframe 的工作方式非常相似,但有一些很酷的功能,我发现它们非常方便:

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

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

于 2008-12-13T23:20:13.590 回答
13

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

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

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

那么,如果我将 '/path/to/fileWithSecrets' 之类的内容传递给该脚本会发生什么?给定的脚本将愉快地发送 webserver-user 可以访问的任何文件。

有关如何防止这种情况的信息,请参阅此讨论:如何确保文件路径在给定的子目录中?

于 2012-12-02T16:16:14.490 回答
10

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

Content-disposition: attachment; filename=fname.ext

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

于 2008-12-13T23:10:54.857 回答
5

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

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

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

于 2013-04-05T23:43:36.527 回答
3

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

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

于 2008-12-13T22:14:33.100 回答
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>
于 2014-03-14T18:26:37.557 回答
2

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

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

于 2008-12-13T22:07:48.963 回答
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() 函数(我在要下载的文件的上一个文件夹的路径中测试了下载文件)我能够快速制作一组“允许”下载的文件,并对照它检查传递的路径. 这不仅确保被抓取的文件不是敏感文件,而且同时检查文件是否存在。

~注: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>
于 2015-08-20T20:46:48.673 回答
1

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

于 2008-12-13T22:24:29.787 回答
1

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

这是解析 ?file= QueryString (取自这个问题)并在 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 和 window.onload 处理程序并在 $(document).ready(function () { } ); 中执行所有操作

于 2013-03-05T23:47:12.397 回答