zoukankan      html  css  js  c++  java
  • 跨域的异步请求二

    说一下JSONP的原理,我们的跨域严重依赖这东西。其实这是一种脚本注入的行为,前后涉及两段脚本片断,并公开一些全局变量。为了放便讲解,我把例子先放出来:

    <!doctype html>
    <html>
      <head>
      <title>jsonp原理 by 司徒正美</title>
      <meta charset="utf-8"/>
      <meta content="IE=8" http-equiv="X-UA-Compatible"/>
      <meta name="keywords" content="jsonp原理 by 司徒正美" />
      <meta name="description" content="jsonp原理 by 司徒正美" />
      <script type="text/javascript" charset="utf-8">
        window.onload = function(){
          var script = document.createElement("script");
          window.jsonpCallBack = function(json){
            for(var item in json){
              alert(item)
            }
            if(window.JSON){
              alert(window.JSON.stringify(json))
            }
          }
          script.src = "http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=jsonpCallBack"
          var head = document.getElementsByTagName("head")[0];
          head.appendChild(script);
        }
      </script>
    
    </head>
    <body>
      <h1>JSONP原理by 司徒正美</h1>
    
    </body>
    </html>
    

    这个页面上有一个内部脚本,我称之为脚本片断1。它将在页面加载后,动态生成一个script标签,设置src并加入DOM树中。重点就是这个src的构成,它是一个普通url与一些查询参数组成的。这些查询参数视公司而定,但其中用一个肯定是用来标识回调函数的名字。我这里是jsonpCallBack,既然有函数名,必然要有函数本身。由于我们定义这函数时,不一定在全局作用域下,因此我为它加了个“window前缀”。有一个有趣的比喻说,全局作用域就像一个公共厕所,虽然你免不了要去它那里,但你也应该少去它那里。如果可能,我们在使用了它以后,也应该努力打扫一下它,避免全局变量过多,减少命名冲突的风险。不过,现在我们不打扫了,这还涉及一个问题。我们看后台是怎么处理的。

    既然是这script标签添加src属性,它理应是一个JS文件,要不会报错,在标准浏览器下我们可以使用onerror来监听它。但现在我们怎么看它也不是一个JS文件。这就全然靠目标服务器的造化了!当我们把这段奇怪的东西发送过去时,它应该会把这些参数与函数名进行分解,根据参数生成一个JSON,写入一个JS文件(动态生成的),然后取得函数名,由于这是一个全局函数,可以直接调用。嘛,反正此时是文本状态,在函数名加一对括号,把JSON放到中间便是。换言之,这个JS文件是这个样子:

    //动态加载的新JS文件
          var json = {"title":"Recent Uploads tagged cat",
            "link":"http://www.flickr.com/photos/tags/cat/",
            "description":"",
            "modified":"2010-05-25T17:21:19Z",
            "generator":"http://www.flickr.com/",
            "items":[/**很多很多的数据,这里略**/]}
          window.jsonpCallBack(json) 
    

    因此,一旦这JS文件被解析,就能执行回调函数与处理我们请求回来的数据(JSON)。好了,是时候打扫一下了。首先这个用于后台交互的script标签,在回调函数执行完没有用了,我们可以移除它。另,回调函数执行完了,这个函数也没有用了,也可以移除了。

            window.jsonpCallBack = function(json){
              for(var item in json){
                alert(item)
              }
              if(window.JSON){
                alert(window.JSON.stringify(json))
              }
    
              script.parentNode && script.parentNode.removeChild( script );
              //这是一种权宜之计,虽然值设为undefined了,但我们还能在for...in循环中遍历出jsonpCallBack
              window.jsonpCallBack = undefined;
              try {
                //彻底删除jsonpCallBack这个成员
                //只可惜IE的window是基于COM,没有delete这方法,因此失败!
                alert(window instanceof Object)
                delete window.jsonpCallBack
              } catch(e) {}
             
            }
    

    注释中也说了,真是请神容易送神难。为了我们需要改变策略,采用单足独立式结构,减少全局污染!换言之,这些回调函数的方法名必须成为某个对象的成员!为了,提高效率,我搞了对象数组(如果只用一个对象来装载它们,for...in循环恶心死了!)

    //小型JSONP类库 by 司徒正美
          var dom = {};//暴露类库唯一一个全局变量作为命名空间
          dom.jsonp = function(url,obj,method){
            var self = arguments.callee;
            if (self.callbacks.length) {//实现异步装载,异步回调
              setTimeout(function() {self(url,obj,method)}, 0);
              return;
            }
            var query =[];
            for(var i in obj){
              query.push(i +"="+obj[i])
            }
            var callback = "dom.jsonp.callback"
            url = url+"?"+ query.join("&")+"&"+method+"="+callback;
            var script = document.createElement("script");
            script.src = url;
            var head = document.getElementsByTagName("head")[0];
            var obj = {
              method:function(json){
                for(var item in json){
                  alert(item)
                }
                if(window.JSON){
                  alert(window.JSON.stringify(json))
                }
                script.parentNode && script.parentNode.removeChild( script );
              }
            }
            dom.jsonp.addCallback(obj)
            head.appendChild(script);
          }
          dom.jsonp.callbacks = []
          dom.jsonp.addCallback = function(obj){
            this.callbacks.push(obj)
          }
          dom.jsonp.callback = function(json){//统一处理回调函数
            var objs = this.callbacks;
            for (var i=0,el;el=objs[i++];) {
              el.method.call(el,json)
            }
            this.callbacks = [];
          }
    
          window.onload = function(){
            dom.jsonp("http://api.flickr.com/services/feeds/photos_public.gne",{
              tags: 'cat',
              tagmode: 'any',
              format: 'json' },"jsoncallback");
            
            dom.jsonp("http://api.cnet.com/restApi/v1.0/techProductSearch",{
              partTag: 'mtvo',
              iod: 'hlPrice',
              viewType: 'json',
              results: '100',
              query: 'ipod'},"callback");
            
            dom.jsonp("http://del.icio.us/feeds/json/fans/stomita",null,"callback");
          }
    

    //http://www.blogjava.net/emu/articles/129240.html var dom = {};//暴露类库唯一一个全局变量作为命名空间 //{url,obj,callbackName,callback} dom.jsonp = function(url,obj,method,callback,caching){ method = method || "callback"; var script = document.createElement('script'); var index = dom.jsonp.index++; var query = dom.toQueryString(obj); callback = callback || function(json){ for(var item in json){ alert(item) } if(window.JSON){ alert(window.JSON.stringify(json)) } } url = url+"?"+ query+"&"+method+"="+escape('dom.jsonp.callbacks._'+index); if (!caching) url += '&rand='+Math.random(); dom.jsonp.callbacks['_'+index] = function() { delete dom.jsonp.callbacks['_'+index]; if (arguments.length==1) { callback(arguments[0]); } else { var arry = []; for (var i=0; i
  • 相关阅读:
    【Leetcode】【Easy】Remove Duplicates from Sorted List
    【Leetcode】【Easy】Pascal's Triangle II
    【Leetcode】【Easy】Pascal's Triangle
    【Leetcode】【Easy】Binary Tree Level Order Traversal II
    【Leetcode】【Easy】Binary Tree Level Order Traversal
    【Leetcode】【Easy】Maximum Depth of Binary Tree
    【Leetcode】【Easy】Minimum Depth of Binary Tree
    【Leetcode】【Easy】Balanced Binary Tree
    【Leetcode】【Easy】Symmetric Tree
    如何使用Action.Invoke()触发一个Storyboard
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1744045.html
Copyright © 2011-2022 走看看