最近做了个项目,其中有项目需求是这样的,点击一个文件链接下载该文件,同时向后台发送请求,在开发过程中问题百出,小编把问题总结分享在脚本之家平台,供大家参考
需求很简单,点击一个文件链接下载该文件,同时向后台发送请求。需求很常见,用户点击下载后通常要进行下载量的统计,统计的话可以利用 script标签 或者 img标签(图片ping) 的跨域能力,将它们的 src 属性指向统计地址,但是这次用了 ajax 进行统计,遂出现了这个问题。
demo 代码如下:
<a id="a" href="http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe" >click</a> <script src="jQuery.js"></script> <script> document.getElementById("a").onclick = function(e) { $.post("data.php"); }; </script>
我们都知道,如果一个 a 标签同时拥有 onclick 事件和 href 属性,onclick 事件的回调会在默认事件(即跳转)之前执行,这也正是可以在 onclick 事件中用类似 e.preventDefault() 的代码去除默认事件(即跳转)的原因。所以以上代码,如果点击 a 标签,首先会执行 onclick 事件的回调,即发送 ajax 请求,理论上,因为代码中的 ajax 是异步的(其实同步也一样),所以会一边请求一边打开下载文件。
chrome、UC、opera、2345浏览器中表现均和预期一致,firefox 下点击能跳出下载文件,但是 ajax 部分报错,IE 下未测试。
一开始的错误想法是,跨域导致报错。当点击下载链接时,ajax 请求会以为页面即将跳到 href 所指的地址,导致浏览器以为该 ajax 跨域。该错误想法很快被推翻,一是因为先进行 ajax 请求,所以请求瞬间并未跨域;二是并未报跨域错误(通常如果是跨域错误控制台会指出);三是如下代码更进一步证明了该错误。
<a id="a" href="http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe" >click</a> <script src="jQuery.js"></script> <script> $.post("data.php"); // data.php sleep(100) </script>
打开该页面,随即进行 ajax 请求,一旦点击了下载按钮,请求即被中止。如果 a 标签的 href 属性值不是文件地址,而是用任意的一个 url 替换,如果点击 a 标签,页面会立即跳转到该标签所指向的地址,页面都不存在了,ajax 自然也就中断了。如果 a 标签指向的是文件地址,在 ff 下是不是也会被一样地解析呢(浏览器以为要跳到该地址了,而将 ajax 中止)?
答案是肯定的,我在 stackoverflow 中找到了答案。
When clicking the download link you are leaving the page, even it does not look so. If there would no file transfer, you would see the requested page.. try to set a target="_blank" or use an iframe as target for the link.
从提问可以看出,2010 年时 chrome 和 ff 都有类似的问题,而 chrome 或者说是 webkit 内核的浏览器在之后的版本迭代中修复了这个问题, ff 则一直将问题留到了现在(个人认为这不太合理)。
知道了问题的根源,解决方案也就呼之欲出了。
方法一:
最简单的方法无非是给 a 标签加上 target="_blank",事实上,通常网页都是这么做的,这也是值得肯定的做法。
方法二:
既然 a 标签的默认行为会使得 ajax 请求中断,那么将 "默认行为" 放在请求之前呢?
<a id="a" href="javascript:;" >click</a> <script src="jQuery.js"></script> <script> document.getElementById("a").onclick = function(e) { location.href = "http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe"; $.post("data.php"); }; </script>
方法三:
设置定时器使请求延迟,但是因为 a 标签的默认跳转不属于 Javascript 线程能控制的范围,所以这个延迟阈值的设置非常重要,我本地测试结果居然是 2ms(也是万万没想到),一般设置为 100ms 左右就 ok 了。 这个方法不优雅,不应该使用 。
<a id="a" href="http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe" >click</a> <script src="jQuery.js"></script> <script> document.getElementById("a").onclick = function(e) { setTimeout(function() { $.post("data.php"); }, 100); }; </script>
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
细数Ajax请求中的async:false和async:true的差异
以上是Ajax请求过程中下载文件在FireFox(火狐)浏览器下的兼容问题的详细内容。更多信息请关注PHP中文网其他相关文章!