zoukankan      html  css  js  c++  java
  • Ajax异步导出方案

    可能一些技术细节涉及到架构实现方案,不过,不影响本意的表达。

    跨页面传值(按查询的导出方案)

    场景:页面类型:查询条件,查询,导出。

    查询条件比较多,且查询内容也可能比较多,如果使用URL传值的话,可能存在URL超长截断的可能。

    原理:

    1.  问题:在回调(Ajax或timer)里执行 document.location 或 window.open 方法,浏览器会阻止下载(有提示)。要解决,如何把条件 Post 到服务器端,再执行 window.location 方法而不报阻止 。

    2. 导出时,先使用 Ajax 把查询Model 传递到服务器,保存在Session 里。

    3. 执行 window.location 跳转。

    4. 跳转页面检查Session 里的查询Model,如果不存在,则进行阻塞等待,等待最大时间 3秒。 如果超时,则抛出错误,如果3秒内得到 Ajax 传递回来的查询Model,则继续执行。

    实现方案:

    1. 客户端传值,先调用 jv.saveSession , 再弹出页面传递参数 : QueryKey。

    jv.saveSession("ParkingInfo", $(".divQuery:last", jv.boxdy()).GetDivJson("List_"));

    jv.PopList({

    url: "~/ReportWeb/Parking/ParkingInfo.aspx?QueryKey=ParkingInfo",

    entity: "Notices"

    }, null);

    2. 服务器端接收(只能接收一次)

    var qModel = LifeSession.OnceGetQuery(Request.QueryString["QueryKey"], new ParkingBiz.ParkingQuery());

    if (qModel == null)

    {

    Response.Write("接收参数时失败,请重试,或联系系统管理员。");

    Response.End();

    }

    当然 LifeSession

    View Code
        public class LifeSession : IDisposable
        {
            List<string> keys = new List<string>();
            public object this[string SessionKey]
            {
                get
                {
                    return HttpContext.Current.Session[SessionKey];
                }
                set
                {
                    GodError.Check(value == null, () => "数据接收异常");
                    keys.Add(SessionKey);
                    HttpContext.Current.Session[SessionKey] = value;
                }
            }
            public void Dispose()
            {
                keys.All(o =>
                {
                    HttpContext.Current.Session.Remove(o);
                    return true;
                });
            }
    
            public static T OnceGetQuery<T>(string Key, T NewModel)
                where T : class
            {
                if (Key.HasValue() == false)
                {
                    throw new GodError("接收Session值的 Key 值不能为空");
                }
    
                XmlDictionary<string, string> dict = null;
    
                //10 sec
                for (int i = 0; i < 100; i++)
                {
                    if (HttpContext.Current.Session[Key] != null)
                    {
                        dict = HttpContext.Current.Session[Key] as XmlDictionary<string, string>;
    
                        if (dict == null)
                        {
                            var err = "数据接收异常 :" + HttpContext.Current.Session[Key].GetType().FullName;
                            LogInfo.To(InfoEnum.Error, MySessionKey.UserName.Get(), err);
                            throw new GodError(err);
                        }
    
                        HttpContext.Current.Session.Remove(Key);
                        break;
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
                if (dict == null) return null;
                var retVal = dict.DictionaryToModel(NewModel);
                GodError.Check(retVal == null, () => "Session项数据 : " + Key + "转换失败, 数据:" + dict.ToJson() + ",转换目标类型:" + typeof(T).FullName);
                return retVal;
            }
        }

    js:

    View Code
        jv.saveSession = function (sessionKey, jsonData) {
            if (!sessionKey) { alert("请输入 SessionKey "); return false; }
            if (!jsonData) { alert("请输入 JsonData "); return false; }
    
            $.post(jv.Root + "Master/Home/SaveSession/" + sessionKey + ".aspx", jsonData, function (res) {
                if (res.msg) { alert(res.msg) };
            });
            return true;
        };

    执行流程

    点击导出后,其流程图是这样的:

    1. Client   ----------------------------------------------IIS加工并赋Session---->     保存Session

    2. Client   ----------------------IIS加工并赋Session-----> 取Session

    其中: 1和2 到达服务器时间不确定,上图只说明其中一种特例出错的情况.

    出现的问题

    当Session超时后,再执行导出,取不到 Session , 调试发现:  当Session 超时后, 保存 Session 时, Session 的 IsNewSession 是 true .但这不重要. 重要的是,它们是两个线程,当第2 个线程早到的时候,先执行了Session 的赋值,也就是说已过了IIS赋Session的时间,再也取不到 1号线程赋的Session, 这两个线程之间不能共享值.

    解决方法

    因为要清空数据,所以可以换用 全局静态变量  public static Dictionary<string,StringDict>  App {get;set;} 来保存 Session 值。 其Key 是 SessionId 和 原SessionKey 在 OnceGetQuery 时,清除该Key值,即可。

    改造后的代码:

            [HttpPost]
            [ValidateInput(false)]
            public ActionResult SaveSession(string uid, FormCollection query)
            {
                if (uid.HasValue())
                {
                    LifeSession.App[Session.SessionID + "_" + uid.Trim()] = query.ToStringDict();
                }
                return new JsonMsg();
            }
        public class LifeSession : IDisposable
        {
            public static Dictionary<string, StringDict> App { get; set; }
    
            static LifeSession()
            {
                App = new Dictionary<string, StringDict>();
            }
    
    
            List<string> keys = new List<string>();
            public object this[string SessionKey]
            {
                get
                {
                    return HttpContext.Current.Session[SessionKey];
                }
                set
                {
                    GodError.Check(value == null, () => "数据接收异常");
                    keys.Add(SessionKey);
                    HttpContext.Current.Session[SessionKey] = value;
                }
            }
            public void Dispose()
            {
                keys.All(o =>
                {
                    HttpContext.Current.Session.Remove(o);
                    return true;
                });
            }
    
            public static T OnceGetQuery<T>(string Key, T NewModel)
                where T : class
            {
                if (Key.HasValue() == false)
                {
                    throw new GodError("接收Session值的 Key 值不能为空");
                }
    
                XmlDictionary<string, string> dict = null;
    
                Key = HttpContext.Current.Session.SessionID + "_" + Key;
    
                //10 sec
                for (int i = 0; i < 100; i++)
                {
                    if (App.ContainsKey(Key))
                    {
                        dict = App[Key] as StringDict;
    
                        if (dict == null)
                        {
                            var err = "数据接收异常 :" + App[Key].GetType().FullName;
                            LogInfo.To(InfoEnum.Error, MySessionKey.UserName.Get(), err);
                            throw new GodError(err);
                        }
    
                        App.Remove(Key);
                        break;
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
                if (dict == null) return null;
                var retVal = dict.DictionaryToModel(NewModel);
                GodError.Check(retVal == null, () => "Session项数据 : " + Key + "转换失败, 数据:" + dict.ToJson() + ",转换目标类型:" + typeof(T).FullName);
                return retVal;
            }
        }

    完毕。

    alarm   作者:NewSea     出处:http://newsea.cnblogs.com/    QQ,MSN:iamnewsea@hotmail.com

      如无特别标记说明,均为NewSea原创,版权私有,翻载必纠。欢迎交流,转载,但要在页面明显位置给出原文连接。谢谢。
  • 相关阅读:
    ubuntu16.04解决播放swf视频文件问题
    ubuntu下设置clion是使用clang和clang++
    Linux 下没有conio.h 已解决
    适合最新版docker自定义启动配置
    nginx限制ip并发数
    nginx 403错误
    ubuntu 支持中文
    CentOS 5 上使用yum同时安装32位和64位包的解决方法
    rhel yum报错
    因为swap分区无法启动
  • 原文地址:https://www.cnblogs.com/newsea/p/2717679.html
Copyright © 2011-2022 走看看