• AjaxPro 原理


    前面2篇文章我介绍了AJAXPro的一些实际应用.但是其基本的原理还不是很清楚,感觉做技术的,
    最好还是"知其然知其所以然",这样才可以做到"有的放矢".

    现在我们从头开始,了解AJAXPro的处理方式.

    首先,我们在Web.config中添加了一段httpHandler注册.

    <add path="*.ashx" verb="*" type="AjaxPro.AjaxHandlerFactory,AjaxPro.2"/>

    这样,所有以ashx结尾的文件都由AjaxPro.AjaxHandlerFactory这个httpHandler处理.

    打开使用AJAXPro注册的页面(就是使用AjaxPro.Utility.RegisterTypeForAjax(typeof(页面类))的页面).
    查看其代码:发现他添加了4段js代码:

    <script type="text/javascript" src="/ajaxpro/prototype.ashx"></script>
    <script type="text/javascript" src="/ajaxpro/core.ashx"></script>
    <script type="text/javascript" src="/ajaxpro/converter.ashx"></script>
    <script type="text/javascript" src="/ajaxpro/SD2007.Test.Test1,SD2007.ashx"></script>
    prototype.ashx就是prototype.js.一个著名的js开源AJAX框架.(地球人都知道吧!)
    core.ashx是什么呢?
    他其实就是一个js的类,这个类的作用是创建XMLHttpRequest对象进行异步操作.还有,XMLHttpRequest是依赖于浏览器的.
    如果浏览器不能创建,则创建一个IFrameXmlHttp类来进行异步操作,也就是创建一个iframe.
    converter.ashx是一个转换对象,用来把.Net数据类型转换到js中使用.前面一篇我的函数返回的是一个Hashtable 对象,但
    他则转换成2维的数组.这个对象可以转换很多的.net数据类型.
    SD2007.Test.Test1,SD2007.ashx就是我们页面注册AJAXPro对象产生的文件,他的代码不长,如下:
    if(typeof SD2007 == "undefined") SD2007={};
    if(typeof SD2007.Test == "undefined") SD2007.Test={};
    SD2007.Test.Test1_class 
    = function() {};
      Object.extend(SD2007.Test.Test1_class.prototype, Object.extend(
    new AjaxPro.AjaxClass(), {
        GetCity: 
    function(sName) {
          return this.invoke("GetCity", {"sName":sName}, this.GetCity.getArguments().slice(1));
        },
        url: '
    /ajaxpro/SD2007.Test.Test1,SD2007.ashx'
    }));
    SD2007.Test.Test1 
    = new SD2007.Test.Test1_class();
    他利用prototype建立对象,并"继承"对象AjaxPro.AjaxClass,扩展一个GetCity方法,这个方法invoke调用ASP.Net里
    注册为AJAXPro.Method的
    GetCity方法.也就是异步操作的核心.他其实也是利用其他的js框架来实现异步数据的操作,不
    过"异步的调用一个方法"而已.
    我们现在看看其invoke方法的实现(红色的注释是我自己添加上去的):
    invoke: function(method, args, callback, context) {
            
    this.__start = new Date().getTime();

            
    // if(this.xmlHttp == null) {
                this.xmlHttp = new XMLHttpRequest();  //建立异步对象

            
    // }

            
    this.isRunning = true;
            
    this.method = method;
            
    this.args = args;
            
    this.callback = callback;
            
    this.context = context;
            //是否使用异步操作
            
    var async = typeof(callback) == "function" && callback != AjaxPro.noOperation;
            
            
    if(async) {
                
    if(MS.Browser.isIE) {
                    
    this.xmlHttp.onreadystatechange = this.doStateChange.bind(this);
                } 
    else {
                    
    this.xmlHttp.onload = this.doStateChange.bind(this);
                    
    this.xmlHttp.onerror = this.mozerror.bind(this);
                }
                
    this.onLoading(true);
            }
            
            
    var json = AjaxPro.toJSON(args) + ""//转换成JSON数据
            //下面做什么的不知道,好像是用了加密数据的
            if(AjaxPro.cryptProvider != null && typeof AjaxPro.cryptProvider.encrypt == "function")     {
                json 
    = AjaxPro.cryptProvider.encrypt(json);
            }
            
            
    this.xmlHttp.open("POST"this.url, async);  //post数据
            
    this.xmlHttp.setRequestHeader("Content-Type""text/plain; charset=utf-8");
            
    this.xmlHttp.setRequestHeader("X-" + AjaxPro.ID + "-Method", method);
            
            
    if(AjaxPro.token != null && AjaxPro.token.length > 0) {
                
    this.xmlHttp.setRequestHeader("X-" + AjaxPro.ID + "-Token", AjaxPro.token);
            }

            
    /* if(!MS.Browser.isIE) {
                this.xmlHttp.setRequestHeader("Connection", "close");
            } 
    */
            //超时处理
            
    this.timeoutTimer = setTimeout(this.timeout.bind(this), AjaxPro.timeoutPeriod);
            //发送数据
            
    trythis.xmlHttp.send(json); }catch(e){}    // IE offline exception

            
    if(!async) {
                
    return this.createResponse({error: null,value: null});
            }

            
    return true;    
        }
    };
    发现就是js调用XMLHttpRequest对象,然后发生数据进行异步操作而已.不过加了其他的一些他的代码.不过其中的

    doStateChange函数比较的重要,他将会在服务端返回后执行.

    doStateChange: function() {
            
    this.onStateChanged(this.xmlHttp.readyState, this);
            
    if(this.xmlHttp.readyState != 4 || !this.isRunning) {
                
    return;
            }
            
    this.duration = new Date().getTime() - this.__start;
            
    if(this.timeoutTimer != null) {
                clearTimeout(
    this.timeoutTimer);
            }
            
    var res = this.getEmptyRes();
            
    if(this.xmlHttp.status == 200 && this.xmlHttp.statusText == "OK") {
                res 
    = this.createResponse(res);
            } 
    else {
                res 
    = this.createResponse(res, true);
                res.error 
    = {Message:this.xmlHttp.statusText,Type:"ConnectFailure",Status:this.xmlHttp.status};
            }
            
            
    this.endRequest(res);
        },

     如果 status 是 200,也就是 OK,那么清除掉超时处理函数,最后使用 callback 调用 createResponse 函数
    还记得如果不是异步的话,createResponse 将会直接调用而不是通过 doStateChange 吧。

    下面我们继续看看createResponse函数

    createResponse: function(r, noContent) {
            
    if(!noContent) {
                
    if(typeof(this.xmlHttp.responseText) == "unknown") {
                    r.error 
    = {Message: "XmlHttpRequest error reading property responseText.", Type: "XmlHttpRequestException"};
                    
    return r;
                }
                
    var responseText = "" + this.xmlHttp.responseText; 
                //解密数据
                
    if(AjaxPro.cryptProvider != null && typeof AjaxPro.cryptProvider.decrypt == "function") {
                    responseText 
    = AjaxPro.cryptProvider.decrypt(responseText);
                } 

                
    if(this.xmlHttp.getResponseHeader("Content-Type"== "text/xml") {
                    r.value 
    = this.xmlHttp.responseXML;
                } 
    else {
                    
    if(responseText != null && responseText.trim().length > 0) {
                        r.json 
    = responseText;
                        
    var v = null;
                        eval(
    "v = " + responseText + ";");
                        
    if(v != null) {
                            
    if(typeof v.value != "undefined") r.value = v.value;
                            
    else if(typeof v.error != "undefined") r.error = v.error;
                        }
                    }
                }
            }
            
    /* if(this.xmlHttp.getResponseHeader("X-" + AjaxPro.ID + "-Cache") == "server") {
                r.isCached = true;
            } 
    */
            //返回响应的数据
            
    return r;
        } 


    如果前面的 json 也就是 Request 是加过密的,这里就需要对 responseText 进行解密。完了之后得到 r.value,r 将会被返回并提供给 callback 函数。r 被传入它的 res 参数。整个 Ajax ClientScript 的流程就差不多是完成了。

    AJAXPro大概原理的探究已经差不多了,看完了他的实现,我才发现js真的是一个很"强悍"的语言.学好了,在web开
    发上将会如虎添翼.

    下篇介绍:(四)AJAXPro之旅---AJAXPro类库的探索...

    (特补上IFrameXmlHttp的分析(加了注释了):)

    AjaxPro.IFrameXmlHttp.prototype = {
        onreadystatechange: 
    null, headers: [], method: "POST", url: null, async: true, iframe: null,
        status: 
    0, readyState: 0, responseText: null,
        abort: 
    function() {
        },
        readystatechanged: 
    function() {
            
    var doc = this.iframe.contentDocument || this.iframe.document;
            
    if(doc != null && doc.readyState == "complete" && doc.body != null && doc.body.res != null) {
                
    this.status = 200;
                
    this.statusText = "OK";
                
    this.readyState = 4;
                
    this.responseText = doc.body.res;    //设置响应文本为IFrame的documnet的内容
                this.onreadystatechange();
                
    return;
            }
            setTimeout(
    this.readystatechanged.bind(this), 10);
        },
        open: 
    function(method, url, async) {
            
    if(async == false) {
                alert(
    "Synchronous call using IFrameXMLHttp is not supported.");
                
    return;
            }
            
    if(this.iframe == null) {
                
    var iframeID = "hans";
                
    if (document.createElement && document.documentElement &&
                    (window.opera 
    || navigator.userAgent.indexOf('MSIE 5.0') == -1))
                {
                    
    //建立iframe
                    var ifr = document.createElement('iframe');
                    ifr.setAttribute('id', iframeID);
                    ifr.style.visibility 
    = 'hidden';    //隐藏iframe
                    ifr.style.position = 'absolute';
                    ifr.style.width 
    = ifr.style.height = ifr.borderWidth = '0px';

                    
    this.iframe = document.getElementsByTagName('body')[0].appendChild(ifr);   //添加到body
                }
                
    else if (document.body && document.body.insertAdjacentHTML)
                {
                    
    //也是建立iframe,考虑到浏览器兼容性
                    document.body.insertAdjacentHTML('beforeEnd', '<iframe name="' + iframeID + '" id="' + iframeID + '" style="border:1px solid black;display:none"></iframe>');
                }
                
    //设置iframe变量为刚才建立的iframe DOM对象
                if (window.frames && window.frames[iframeID]) {
                    
    this.iframe = window.frames[iframeID];
                }
                
    this.iframe.name = iframeID;
                
    this.iframe.document.open();
                
    this.iframe.document.write("<"+"html><"+"body></"+"body></"+"html>");
                
    this.iframe.document.close();
            }
            
    this.method = method;
            
    this.url = url;
            
    this.async = async;
        },
        
    //建立响应头
        setRequestHeader: function(name, value) {
            
    for(var i=0; i<this.headers.length; i++) {
                
    if(this.headers[i].name == name) {
                    
    this.headers[i].value = value;
                    
    return;
                }
            }
            
    this.headers.push({"name":name,"value":value});
        },
        getResponseHeader: 
    function(name, value) {
            
    return null;
        },
        
    //建立input ,如果数据有回车则建立textarea
        addInput: function(doc, form, name, value) {
            
    var ele;
            
    var tag = "input";
            
    if(value.indexOf("\n">= 0) {
                tag 
    = "textarea";
            }
            
            
    if(doc.all) {
                ele 
    = doc.createElement("<" + tag + " name=\"" + name + "\" />");
            }
    else{
                ele 
    = doc.createElement(tag);
                ele.setAttribute(
    "name", name);
            }
            ele.setAttribute(
    "value", value);
            form.appendChild(ele);
            ele 
    = null;
        },
        send: 
    function(data) {
            
    if(this.iframe == null) {
                
    return;
            }
            
    var doc = this.iframe.contentDocument || this.iframe.document;
            
    var form = doc.createElement("form");
            
    //建立一个form.设置其参数
            doc.body.appendChild(form);
            
            form.setAttribute(
    "action"this.url);
            form.setAttribute(
    "method"this.method);
            form.setAttribute(
    "enctype""application/x-www-form-urlencoded");
            
            
    for(var i=0; i<this.headers.length; i++) {
                
    switch(this.headers[i].name.toLowerCase()) {
                    
    case "content-length":
                    
    case "accept-encoding":
                    
    case "content-type":
                        
    break;
                    
    default:
                        
    this.addInput(doc, form, this.headers[i].name, this.headers[i].value);
                }
            }
            
    //建立input ,如果数据有回车则建立textarea
            this.addInput(doc, form, "data", data);
            form.submit();    
    //提交数据
            
            setTimeout(
    this.readystatechanged.bind(this), 0);
        }
    };

     引用:http://www.cnblogs.com/eicesoft/archive/2007/09/12/890759.html

  • 相关阅读:
    Python PyQt5 Pycharm 环境搭建及配置
    Python Appium 元素定位方法简单介绍
    unittest单元测试简单介绍
    什么是multipart/form-data请求
    new HttpClient().PostAsync封装参数
    httpPostedFile实现WEBAPI文件上传
    Asp.Net WebApi接口返回值IHttpActionResult
    Asp.Net WebApi上传图片
    如果项目在IIS发布后,出现System.ComponentModel.Win32Exception: 拒绝访问。
    C# ASP.NET 控制windows服务的 开启和关闭 以及重启
  • 原文地址:https://www.cnblogs.com/chencidi/p/1732972.html
Copyright © 2020-2023  润新知