假设我的网站上有文件的下载链接。
当点击这些链接时,会向服务器发送一个 AJAX 请求,服务器会返回带有文件位置的 URL。
我想要做的是在响应返回时指示浏览器下载文件。有没有便携的方法来做到这一点?
假设我的网站上有文件的下载链接。
当点击这些链接时,会向服务器发送一个 AJAX 请求,服务器会返回带有文件位置的 URL。
我想要做的是在响应返回时指示浏览器下载文件。有没有便携的方法来做到这一点?
我们这样做:首先添加这个脚本。
<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 凭证等。
我创建了一个开源jQuery 文件下载插件(带有示例的演示)(GitHub),它也可以帮助您解决问题。它与 iframe 的工作方式非常相似,但有一些很酷的功能,我发现它们非常方便:
只需window.location.href = new_url
从您的 javascript 调用,它就会将浏览器重定向到该 URL,因为它是用户在地址栏中输入的
阅读答案 - 包括已接受的答案,我想指出通过 GET 将路径直接传递给 readfile 的安全隐患。
这对某些人来说似乎很明显,但有些人可能只是复制/粘贴此代码:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
那么,如果我将 '/path/to/fileWithSecrets' 之类的内容传递给该脚本会发生什么?给定的脚本将愉快地发送 webserver-user 可以访问的任何文件。
有关如何防止这种情况的信息,请参阅此讨论:如何确保文件路径在给定的子目录中?
如果这是您自己的服务器应用程序,那么我建议使用以下标头
Content-disposition: attachment; filename=fname.ext
这将强制任何浏览器下载文件而不是在浏览器窗口中呈现它。
试试这个库https://github.com/PixelsCommander/Download-File-JS它比之前描述的所有解决方案都更现代,因为它使用“下载”属性和方法组合来带来最佳体验。
在这里解释 - http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/
似乎是开始在 JavaScript 中下载的理想代码。
同意 maxnk 提到的方法,但是您可能需要重新考虑尝试自动强制浏览器下载 URL。它可能适用于二进制文件,但对于其他类型的文件(文本、PDF、图像、视频),浏览器可能希望在窗口(或 IFRAME)中呈现它,而不是保存到磁盘。
如果您确实需要进行 Ajax 调用以获取最终下载链接,那么使用 DHTML 将下载链接(来自 ajax 响应)动态写入页面怎么样?这样,用户可以单击它进行下载(如果是二进制文件)或在浏览器中查看 - 或在链接上选择“另存为”以保存到磁盘。这是一个额外的点击,但用户有更多的控制权。
要绕过投票最多的答案中的安全漏洞,您可以将 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>
我建议在页面上创建一个不可见的 iframe,并将其 src 设置为您从服务器收到的 url - 下载将在不重新加载页面的情况下开始。
或者您可以将当前的 document.location.href 设置为接收到的 url 地址。但是,如果请求的文档实际上不存在,这可能会导致用户看到错误。
关于最佳答案,我有一个可能的安全风险解决方案。
<?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>
我建议window.open()
打开一个弹出窗口。如果是下载,则没有窗口,您将获得文件。如果有 404 什么的,用户将在新窗口中看到它(因此,他们的工作不会受到打扰,但他们仍然会收到错误消息)。
当您只需要将浏览器重定向到不同的 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 () { } ); 中执行所有操作