ajax请求过程中下载文件在火狐下的兼容问题
项目中碰到的问题,记录如下。
需求很简单,点击一个文件链接下载该文件,同时向后台发送请求。需求很常见,用户点击下载后通常要进行下载量的统计,统计的话可以利用 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>
今天是 2015 年最后一天,祝福辛苦了一年的大小程序猿&程序媛们,元旦快乐,来年大吉!今晚好好休息 or 好好(。・∀・)ノ゙嗨 (如果这个点还在奋战在加班的第一线,也只能深表同情了啊 - -)
ajax请求过程中下载文件在火狐下的兼容问题的更多相关文章
- Ajax请求过程中显示“进度”的简单实现
Ajax在Web应用中使用得越来越频繁.在进行Ajax调用过程中一般都具有这样的做法:显示一个GIF图片动画表明后台正在工作,同时阻止用户操作本页面(比如Ajax请求通过某个按钮触发,用户不能频繁点击 ...
- 统一处理jquery ajax请求过程中的异常错误信息的机制
当jQuery ajax向服务器发送请求,服务器发生异常,比如:400.403.404.500等异常,服务器将异常响应给客户端,此时的ajax可以获取异常信息并进行处理,但此时我们一般是跳转到与异常编 ...
- zepto源码研究 - ajax.js(请求过程中的各个事件分析)
简要:ajax请求具有能够触发各类事件的功能,包括:触发全局事件,请求发送前事件,请求开始事件,请求结束事件等等,贯穿整个ajax请求过程,这是非常有用的,我们可以利用这些事件来做一些非常有意思的事情 ...
- ajax用beforeSend自定义请求过程中客户端事件,提高用户体验
本文为博主原创,未经允许不得转载: 在应用ajax的过程中,当我们再前台提交请求的时候,如果服务端响应事件比较长,就会导致需要等很长时间在前台才能接受到服务端返回的 响应结果,往往会导致用户重复点击按 ...
- JS请求服务器,并返回信息,请求过程中不需要跳转页面
js请求服务器,并返回信息,请求过程中不需要跳转页面 这个可以通过jQuery框架轻松实现,jQuery中包含多种ajax的请求方式,详细可以参考下对应 的API. 你上面定义的按钮类型是submit ...
- 想抛就抛:Application_Error中统一处理ajax请求执行中抛出的异常
女朋友不是想抛就抛,但异常却可以,不信请往下看. 今天在MVC Controller中写代码时,纠结了一下: public async Task<ActionResult> Save(in ...
- VSTO学习笔记(四)从SharePoint 2010中下载文件
原文:VSTO学习笔记(四)从SharePoint 2010中下载文件 上一次我们开发了一个简单的64位COM加载项,虽然功能很简单,但是包括了开发一个64位COM加载项的大部分过程.本次我们来给CO ...
- SpringMVC实现从磁盘中下载文件
除了文件的上传我们还需要从磁盘下载 实现文件的下载只要编写一个控制器,完成读写操作和响应头和数据类型的设置就可以了 下面演示的是从G盘imgs文件夹中下载文件 具体代码如下 package com.c ...
- H5 FormData对象的使用——进行Ajax请求并上传文件
XMLHttpRequest Level2 添加了一个新的接口——FormData .[ 主要用于发送表单数据,但也可以独立使用于传输键控数据.与普通的Ajax相比,它能异步上传二进制文件 ] 利用F ...
随机推荐
- .Net Attribute详解(上)-Attribute本质以及一个简单示例
Attribute的直接翻译是属性,这和Property容易产生混淆,所以一般翻译成特性加以区分.Attribute常常的表现形式就是[AttributeName], 随意地添加在class, met ...
- Tomcat:bio nio 的设计
BIO 由Acceptor接收Socket,将其转交给Worker来处理. NIO 由Acceptor接收Socket,将其转交给Poller来轮询处理.Poller再将可处理的Socket交给Wo ...
- React Native初试:Windows下Andriod环境搭建
最近想写个App,又觉得Native App 太无趣了Web App又没那么成熟然后发现了Facebook在9月发布的React Native比较新奇,所以决定捣鼓看看: React Native为F ...
- iOS 实现Tabbarcontroller中间自定义样式 最简单的方法
先上图: 如果我们要实现中间按钮自定义样式,方法应该蛮多,这里介绍一种最简单的. 1.创建类继承:UITabBarController,如下代码都是写在该类的 .m文件里 2.定义最中间的自定义样式, ...
- linux系统的任务计划crontab使用详解
linux系统的任务计划crontab使用详解 其实大部分系统管理工作都是通过定期自动执行某一个脚本来完成的,那么如何定期执行某一个脚本呢?这就要借助linux的cron功能了. 关于cron任务计划 ...
- Ubuntu13.04安装历险记--Mono,Nginx,Asp.Net一个都不能少
----Ubuntu13.04安装历险记--新人新手新作------------------------------------------------- 注:以下操作均省略权限获取操作,如有需要,请 ...
- discuz mysqli_connect() 不支持 advice_mysqli_connect
看网友的解决方案是:下面2行去掉注释 ? 1 2 ;extension=php_mysql.dll ;extension=php_mysqli.dl 尝试修改 ? 1 #vi /etc/php.i ...
- 浅谈 Linux 内核无线子系统
浅谈 Linux 内核无线子系统 本文目录 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 L ...
- (一)半小时开发一个APP
[前言] HPP是什么? HybirdApp的简称,详细介绍参见:HPP--让所有中小企业拥有自己的APP 说白了就是用html+css+js开发app,包括ios和android版本. HBuild ...
- 使用Windows Azure的VM安装和配置CDH搭建Hadoop集群
本文主要内容是使用Windows Azure的VIRTUAL MACHINES和NETWORKS服务安装CDH (Cloudera Distribution Including Apache Hado ...