zoukankan      html  css  js  c++  java
  • 浏览器监听文件下载实现

    之前在做类似下载功能的时候,很少会考虑那些优化问题。直接一个超链接了事。

    然后。。。我遇到了两个坑。

    坑1,A项目中的导出按钮,测试妹纸在火狐浏览器上死活点不出来,而我自己的火狐上是正常的,最后我发现,是迅雷下载插件惹的祸T。T 

    坑2,B项目中,某运营连续点了10次导出按钮,然后。。。网站变得很卡。

    对于坑1,我们可以用iframe去实现下载。

    $('#J-download').on('click',function(){
      var iframe=$('<iframe />').attr('src', url).attr('id','iframe_download_report').hide().appendTo('body'); 
    });

    而对于坑2,

    首先我需要做连续点击的限制:

    利用setTimeout设置一个触发延时,1秒以内的连续点击都只算做一次。但是事实上很少会有这样的恶意点击,这种控制就很显得很鸡肋。

    而最重要的一点就是做到“waiting”效果,点击下载按钮后就禁用该按钮,同时按钮文本显示“下载中”,等到浏览器开始下载,再启用该按钮,重置按钮文本。

    所以问题的关键就是如何监听到文件下载。

    最开始的思路想到了iframe的onload事件,iframe加载html页面,确实会触发onload事件,但是下载却不会。又想到了异步下载,也被我否决。第二天开会的时候,我问到这个问题的解决办法,一位后端提到他们已有解决方案就是使用cookie,豁然开朗。想到之前百度时在stack overflow上被我匆匆一瞥忽略的cookie和token,原来答案很早就有了冏rz

    思路大致是这样:

    前端生成一个唯一的token,以get方式随url传给后端。后端将token写进cookie中,而前端通过定时器获取,然后核对前端生成的token和通过cookie获取的token值是否一致。

    生成唯一的token,这个可以用new Date()结合随机数做:

    _setFormToken:function(){
        return ""+(Math.random()*1024|0)+new Date().getTime();
    }

    禁用启用链接,因为超链接不支持disabled属性,我们可以操作它的href属性~~

    其他的就很简单了,只要检测到token一致,就启用链接,然后移除iframe。如果没有获取到token或者token不一致,就继续setTimeout。

            _iframeDownLoad:function(){
                var timer,_this=this,flag=0;
                $(document).on('click','.J_DownLog',function(){
                    var downloadToken=_this._setFormToken(),
                        url=this.href+"&downloadToken="+downloadToken,
                        triggerDelay = 1000,
                        btn=$(this);
    
                    _this._disableLink(btn,"导出中...");
                    clearTimeout(timer);
                    
                    timer=setTimeout(function() {
                        function checkToken(){
                            sertoken=_this._getCookie( "downloadToken" );
                            if(sertoken==downloadToken){
                                    clearTimeout( downloadTimer );
                                    _this._expireCookie( "downloadToken" );
                                    frame.remove();
                                    _this._enableLink(btn,"导出日志");
                                    flag=0;
                            }else{
                                checkToken();
                            }
                        }
                        if(!flag){
                            flag=1;
                            var frame=$('<iframe />').attr('src', url).attr('id','iframe_download_report').hide().appendTo('body'); 
                            var downloadTimer=setTimeout(checkToken,1000);                        
                        }
    
                    }, triggerDelay);
                    return false;
                    
                });
            }

     -----------------后续------------------

    2015.04.28

    模拟了下低网速的情况,发现浏览器获取token与弹窗下载对话框之间有时间差,如果每次都是点击导出时添加新的iframe/导出后移除iframe,就会产生iframe过早移除的情况,这样下载对话框就弹不出来了。所以,需要修改为第一次生成iframe,之后都是修改iframe的地址。

  • 相关阅读:
    vue hover如何触发事件?
    防止 window.open 被拦截
    input输入框change和blur事件区别
    神马?使用JS直接上传并预览粘贴板的图片?
    删除设备与驱动器中百度网盘图标
    枚举类字典代码 草稿
    中文转换成阿拉伯数字
    Java对象与类中的一个小练习
    正向代理和反向代理
    MySQL教程126-MySQL事务隔离级别
  • 原文地址:https://www.cnblogs.com/qianlegeqian/p/4409565.html
Copyright © 2011-2022 走看看