javascript跨域请求解决方法总结

javascript中有同源策略,javascript存在跨域通信的问题。典型例子如:Ajax无法直接请求跨域的普通文件,存在跨域无权限访问的问题。

几种常见的解决方法:

1.JSONP  2. window.name+frame 3.document.domain + iframe 4.iframe+location.hash 5.HTML5 postMessage 方法

一、JSONP

    web页面上只有<script><img><iframe>这些拥有“src”属性的标签是拥有跨域能力的。所以当前解决跨域的JSONP方案就是通过<script>的这一特性来实现的。

   原理:<script>标签的src属性是没有跨域的限制的。所以JSONP动态创建一个<script>标签,将本地方法名作为请求参数传递给src属性的url,服务器端获取请求中该参数即客户端的函数名,与要返回给库户端的json数据拼接成一个函数调用的javascript语句,返回给客户端,客户端获取返回的javascript语句并执行,该javascript函数的入参即为服务器端拼接的json数据,用这样的方法来实现在客户端来对异域服务器返回的请求数据进行处理。

    简单概括即,JSONP返回给客户端一串javascript脚本的字符串,脚本中封装json数据。所以这个就决定了JSONP必须在服务器端对返回数据进行处理,加上callback的函数名

JSONP 的相关ajax方法 :

1.getJSON(url+"?callback=?",data,success(data,status,xhr));

例:

(server.php可以跨域放置,getJSON参数该为响应的地址即可)

function handleclick()
{
    $.getJSON("server.php?callback=?",function(data){
          alert(data.weatherinfo.city+":"+data.weatherinfo.weather);

     });
}

2.get(url+"?callback=?",data,success(data,status,xhr),"jsonp");

例:

function handleclick()
{
    $.get("server.php?callback=?",function(data){
          alert(data.weatherinfo.city+":"+data.weatherinfo.weather);

     },"jsonp");
}

3.$.ajax

例:

$.ajax({

   url:"server.php",

   dataType:"jsonp",

   jsonp:"callback",

   type:"GET",

   success:function(data){

        alert(data.weatherinfo.city+":"+data.weatherinfo.weather);

   } 

   error:function(xhr,errortext,error){

        console.log("requset state:"+xhr.readyState+";errorText:"+errortext);

  }

});

服务器端:

server.php

<?php
    header("Content-Type:text/html;charset=utf-8");
    header("Cache-Control:no-cache");
     $callfunc=$_GET["callback"];
    $content=file_get_contents("http://www.weather.com.cn/data/cityinfo/101190101.html");
     echo $callfunc."(".$content.")";

?>

 

ajax 和 jsonp的本质区别是ajax是通过XMLHttpRequest来获取非本页内容,不能跨域,而jsonp是通过动态添加<script>标签来获取跨域服务器返回的脚本。

缺点:1.服务器端返回给客户端javascript脚本会对客户端产生不安全因素。

          2.需要服务端配合传输相应格式数据。

          3.不能解决不同域两页面之间进行javascript的调用问题。

二、HTML5 postMessage 方法

可以用 iframe.postMessage(json,"*"); 来发送数据。

用onmessage方法来获取跨域的数据

三、window.name + iframe

原理:name在浏览器环境中为一个全局/window对象的属性,且在frame中加载新页面时,name的属性值依旧保持不变。

          则可以先让iframe加载跨域页面,通过window.name属性跨域传输数据,由于同源策略window.name不能访问,所以只要将iframe重新链接到本域页面,然后就可以访问window.name中的数据。

例:a.html:

<script>
    var status=0;
     var data;
    var fr=document.createElement("iframe");
    function frload(){
         if(status == 1)
          {
              data=fr.contentWindow.name;
               alert(data);
               destroyfr(fr);
          }
          else if(status == 0)
          {   
              status=1;
               fr.contentWindow.location.href="proxy.html"
          }
     };
     fr.src="http://xxx.com/b.html";
     fr.style.display="none";
     if(fr.attachEvent){
         fr.attachEvent('onload',frload);
     }else
     {
         fr.onload=frload;
     }
     function destroyfr(ifr)
     {
         ifr.src='about:blank';
          try{
              ifr.contentWindow.document.write('');
               ifr.contentWindow.document.clear();
          }catch(e){}
          ifr.parentNode.removeChild(ifr);
     }
    document.body.appendChild(fr);
</script>

本域代理页面为proxy.html,(也可以直接设置一个空白页面about:blank)

跨域页面:b.html:

<script>
    window.name='{"name":"roy","age":"20"}';
</script>

四、document.domain + iframe

 原理:针对主域相同而子域不同的两个页面,可以通过设置document.domain=“主域” 来解决。

          将 http://www.f.com/a.html 和 http://m.f.com/b.html 都设置document.domain="f.com",然后在a.html中通过iframe加载b.html,则a.html 页面可以通过iframe.contentDocument.getElementById("id"); 来获取b页面数据。

  

五、iframe+location.hash

    原理:改变页面hash不会导致页面刷新,所以通过添加或改变iframe的src链接的hash值来进行跨域传递数据

              a页面创建iframe跨域请求b页面,请求参数置于hash中,b页面从location.hash中获取请求参数生成响应数据,a 和b跨域所以b页面中无法通过parent对象改变a页面的loaction.hash的值。所以需要在b.html中动态创建iframe加载一个和a同域的c页面,将响应数据置于c的loaction.hash中,然后在c页面中则可以通过parent.parent来访问a页面并通过loaction.hash来传递远程页面的返回值

    缺点:数据大小有限,并且数据直接暴露在url中


你可能感兴趣的:(javascript跨域请求解决方法总结)