js方法jsonp处理跨域问题

发布时间:2017-05-08 22:55 编辑:站点网

1.什么是跨域?
就是访问第三方网站,严格来说就是不符合同源策略(同源策略:协议,域名,端口都一样的叫同源,其中有一样不一样就是跨域)

http://localhost:8080/ajax
https://localhsot/tom
这俩地址之间的数据传输属于跨域


2.为什么引出跨域问题
  原生ajx不支持跨域获取数据(出于安全考虑)
ajax的限制:只要你请求的url跟你所在的url不同源,就不允许获取数据。
3.怎么实现跨域
   a.动态创建script标签;(最常用的方式,一个官方的名字是jsonp);
  
什么是jsonp?
json with padding
如何用jsonp的形式解决获取数据跨域的问题。
原理:动态创建script标签,通过scr属性发送请求,从而获取数据。(向第三方发送请求并传入接收响应数据的回调函数名,当第三方接收到响应时,会调用请求发送传过来的函数,将请求数据传入,返回一个object类型的数据)

  

   b.document.domain+iframe的设置;
   c.利用iframe和location.hash(这里的hash指的是url地址里的锚点);
   d.window.name实现的跨域数据传输;
   e.使用h5 postmessage;
   f.利用flash.

3.1 1.跨域可以获取数据,同源同样可以获取数据
   例子:同源模拟jsonp处理跨域问题。
  @1用传统方式获取第三方数据(是同步的,必须放在最上面,不灵活)
   jsonp_src.html
  
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type='text//javascript' src='src='jsonp.php''> </script>
    <script type='text/javascript' >
    //跨域可以获取数据,那同源也可以获取数据
    //传统方式通过src属性能去获取第三方数据,请求目标资源,这里文件类型任意。
    //这里是获取一个php文件的内容,数据内容是一段js文本
    console.log(data); //打印输出一下从服务器获取回来的数据
    </script>
</head>


      jsonp.php  模拟从服务器获取的数据

<?php
//这是一段代码,能够返回到jsonp.html中,会被被解析为一段js代码
echo 'var data=1;';
?>

@2函数方法名不应该写死,应该传入 参数更灵活,methodName=abc,将方法名抽成一个参数传入后台,后台通过$method=$_GET('methodName)来获取
<head>
<script type='text/javascript'>
//如何让接口的调用者决定函数名,传参
    function abc(data){
       console.log(data);
   }
   window.onload=function(){
   //1.创建一个script标签,
  var script=document.createElement('script');
     script.src='jsonp.php?methodName=abc';
     var head=document.getElementsByTagName('head')[0];
          head.appendChild(script);

   }
</script>
</head>
//发送的请求文件的返回类型是一个js文件

//方法名参数已随url发送过去,请求的是一个方法的调用,

//请求的是一个方法的调用,返回数据是一个object


//动态传参
<script type='text/javascript' >

   //动态生成方法名  new Date().getTime()当前时间对应的毫秒数
   //(Math.random()+" ")将数值变成字符串,然后.substr(2)截取掉小数点以前的整数位以及小数点
   
   //对象属性的访问和添加方式有两种 . [可以传变量]   //var obj={}
   //obj.name='qq'    //这里是死的写什么,就表示什么属性
   //obj[name]='qq'   //这里实质上是一个string,直接写表示变量name,'name'表示name属性

  //核心:回调函数的创建,参数的传递(对象的本质是键值对)
     var mName='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));

     //此处创建回调函数,随参数发送请求到服务器,服务器调用回调函数,将结果数据返回到此函数中,返回。
     //在window全局作用域内,所有的变量和函数都是window的成员
     //这句话的作用就是给window对象添加一个自定义属性,这个属性是个方法。
     window[mName]=function(data){
         console.log(data);
      }
   //1.创建一个script标签,回调函数callback='+mName
  var script=document.createElement('script');
     script.src='jsonp.php?callback='+mName;
     var head=document.getElementsByTagName('head')[0];
          head.appendChild(script);
    </script>
</head>

//php数据
<?php  
//这是一段代码,能够返回到jsonp.html中,被解析为一段js代码
// echo 'var data=1;';
// echo 'abc(123)';   //这个字符串表示函数调用,其实就是服务器调用客户端传来的回调函数
//$arr=array(1234,34,5,4);
$arr1=array('name'=>1234,'age'=>34);
//echo 'abc('.json_encode($arr1).')';//Object {name: 1234, age: 34}
$method=$_GET['callback'];
echo $method.'('.json_encode($arr1).')';
?>

  //访问360天气(获取第三方数据)
    <script type='text/javascript'>
    var mName='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
    window[mName]=function(data){
      console.log(data);
    }
     var script=document.createElement('script');
     //访问360天气的请求 _jsonp='+mName  传入接收响应数据的回调函数的名字
      script.src = 'http://cdn.weather.hao.360.cn/api_weather_info.php?app=hao360&_jsonp='+mName+'&code=101010100';

     var head=document.getElementsByTagName('head')[0];
      head.appendChild(script);
    </script>
//请求发送并传入回调函数名字

//第三方调用请求数据时传入的回调函数的名字
//第三方返回的数据,传入回调函数中,object类型的数据




//虚拟机模拟跨域获取数据
<script text='text/javascript'>
     var mName='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
         window[mName]=function(data){
          console.log(data);
         }
     var script=document.createElement('script');
     //'http://tom.com/weather.php?  请求数据,传入回调函数名称,以便接收响应数据
     script.src='http://tom.com/weather.php?_jsonp='+mName;
     var head=document.getElementsByTagName('head')[0];
       head.appendChild(script);
    </script>
//模拟请求数据  weather.php
<?php
    $city = $_GET['_jsonp'];
    //数据库查询过程省略
    //select * from weather where  city = $city;
    $arr = array('temp'=>'35度','direction'=>'风向');
    //调用发送请求时传来的回调函数
    echo  $city.'('.json_encode($arr).')';
?>

4.封装一个属于自己的jsonp方法
      why?之前我们都是按照要求一步一步写出来的,这是面向过程的思想,面向过程代码之间的关联性太强,好多重复代码,不灵活,我们知道javascript是面向对象的语言,所以我们会封住一个jsonp的方法,将公共部分抽离出来,不确定,就是比较灵活的部分,以参数形式传入。
//先使用一下jquery里的封装好的ajax()关于jsonp的处理
<script type='text/javascript' src='js/jquery.js'></script>
    <script type='text/javascript'>
    $(function(){
        $.ajax({
            url:'http://tom.com/weather.php',
            dataType:'jsonp',
            jsonp:'_jsonp',    //这个参数是修改回调函数参数名的,不写默认是callback
            // jsonpCallback:'abc', //这是修改参数的值,不写默认按规则生成字符串作为函数名。
            success:function(data){
                console.log(data);
            }
        })
    })

    </script>

//第三方数据文件  tom.com/weather.php
<?php
    $city = $_GET['_jsonp'];
    $arr = array('temp'=>'35度','direction'=>'风向');
    echo  $city.'('.json_encode($arr).')';
?>

ajaxx原生虽然不能实现跨域,但是jsonp实现原理属于ajax内部的另一个分支,如果数据返回类型是text或者json,是由XMLHttpRequest对象来处理,如果数据返回类型是jsonp,则会走ajax的另一个分之,是由<script></script>标签来处理数据的

//这是ajax异步js原生实现过程


  function ajaxForJson(obj){
     var type='get';
     var dataType='text';
     var url='#';
     var success=function(data){
        console.log(data);
     }
     if(obj.type=='post'){
        type=obj.type;
     }
     if(obj.url){
        url=obj.url;
     }
     if(dataType=='json'){
        dataType=obj.dataType;
     }
     //关于参数的处理
     var param='';
     if(obj.data && typeof obj.data=='object'){
        for(var key in obj.data){
            param+=key+'='+obj.data[key]+'&';
        }
        if(param.length>1){
           param=param.substring(0,param.length-1);
        }
     }

     if(typeof obj.success=='function'){
        success=obj.success;
     }
     var xhr=null;
     //1.创建XMLHttpRequest对象
     if(window.XMLHttpRequest){
        xhr=new XMLHttpRequest();
     }else{
        xhr=new ActiveXObject('Microsoft.XMLHTTP');
     }
     if(type=='get'){
        param=encodeURI(param);
        url+='?'+param;
     }
     //2.准备发送请求
     xhr.open(type,url,true);
    var data=null;
     if(type=='post'){
         data=param;
       xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
     }
     //3.发送请求
     xhr.send(data);
     //4.处理返回数据
     xhr.onreadystatechange=function(){
        if(xhr.readyState==4){    //接收到响应,并返回数据,但数据是否正常不知道
            if(xhr.status==200){    //数据正常
                var data=xhr.responseText;
                if(obj.dataType=='json'){ //返回数据类型是json,要转成object
                    data=JSON.parse(data);
                }
                success(data);
            }
        }

     }
    }


//这是jsonpjs原生的实现原理,走的是ajax的另一个分支。


  function ajaxForJsonp(obj){
     if(obj.dataType=='jsonp'){
        var jsonp='callback';
        if(obj.jsonp){
            jsonp=obj.jsonp;
        }
        var jsonpCallback='jquery'+(new Date().getTime())+'_'+((Math.random()+'').substr(2));
        if(obj.jsonpCallback){
            jsonpCallback=obj.jsonpCallback;
        }
        //定义回调函数
        window[jsonpCallback]=function(data){
            //判断是不是函数
            if(obj.success && typeof obj.success=='function'){
                obj.success(data);
            }

        }
        //处理参数
        var param='';
        //先判断obj.data是不是对象
        if(obj.data && typeof obj.data=='object' ){
            for(var key in obj.data){
                param+=key+'='+obj.data[key]+'&';
            }
        }
        var script=document.createElement('script');
        script.src=obj.url+'?'+param+jsonp+'='+jsonpCallback;
        var head=document.getElementsByTagName('head')[0];
        head.appendChild(script);
     }
    }

//这就是模拟$.ajax()方法中ajax异步和jsonp的内部原理
function ajaxsum(obj){
    if(obj.dataType=='jsonp'){
       ajaxForJsonp(obj);
    }else{
       ajaxForJson(obj);
    }
   }

//这是个跨域请求
<script type='text/javascript' src='js/jsonp_ajax.js'></script>
    <script type='text/javascript'>
ajax({
     url:'http://tom.com/weather.php',
    // url:'ajaxphp.php',
    dataType:'jsonp',
     jsonp:'_jsonp',
     jsonpCallback:'bcd',
    data:{
         name:'zs',
         age:12
    },
    success:function(data){
        console.log(data);
    }
   })
    </script>


###json和jsonp的内部走的是ajax()的两个分支。


//返回数据是函数调用,就是jsonp
bcd({"uname":"zs","$age":"12"})


//这样的数据就是json格式的字符串
{"uname":"zs","$age":"12"}



ie8以上才能用

post.message()---h5新特性,有兼容性
可以用flash  ---考虑兼容的话

更多相关内容:
    无相关信息