跨域问题出现原因和解决方案

一、出现原因

跨域是指a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,或是a页面为ip地址,b页面为域名地址,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。

例如:

URL 说明 是否跨域
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同域名下不同文件
http://www.cnblogs.com/a.js 
http://www.a.com/b.js
不同域名
http://www.a.com:8000/a.js 
http://www.a.com/b.js
同域名下不同端口
http://www.a.com/a.js 
https://www.a.com/b.js
同域名 不同协议
http://www.a.com/a.js 
http://70.32.92.74/b.js
域名和域名对应ip
http://www.a.com/a.js 
http://script.a.com/b.js
主域名相同 子域名不同
http://www.a.com/a.js 
http://a.com/b.js
同一域名,不同二级域名(同上)

二、解决方案

【策略一】:Jsonp:需要目标服务器配合一个callback函数

JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
Json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里,它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入<script>元素,由它向跨源网址发出请求。

JSONP的产生:

1.AJAX直接请求普通文件存在跨域无权限访问的问题,不管是静态页面也好.
2.不过我们在调用js文件的时候又不受跨域影响,比如引入jquery框架的,或者是调用相片的时候
3.凡是拥有scr这个属性的标签都可以跨域例如<script><img><iframe>
4.如果想通过纯web端跨域访问数据只有一种可能,那就是把远程服务器上的数据装进js格式的文件里.
5.而json又是一个轻量级的数据格式,还被js原生支持
6.为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback 参数给服务端

Js 客户端 方案一:

<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
<script type="text/javascript">  
    function jsonpCallback(result) {  
        //alert(result);  
        for(var i in result) {  
            alert(i+":"+result[i]);//循环输出a:1,b:2,etc.  
        }  
    }  
    var JSONP=document.createElement("script");  
    JSONP.type="text/javascript";  
    JSONP.src="http://crossdomain.com/services.php?callback=jsonpCallback";  
    document.getElementsByTagName("head")[0].appendChild(JSONP);  
</script> 

Js 客户端 方案二:

<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
<script type="text/javascript">  
    function jsonpCallback(result) {  
        alert(result.a);  
        alert(result.b);  
        alert(result.c);  
        for(var i in result) {  
            alert(i+":"+result[i]);//循环输出a:1,b:2,etc.  
        }  
    }  
</script>  
<script type="text/javascript" src="http://crossdomain.com/services.php?callback=jsonpCallback"></script>

Jquery 客户端 方案一:

<script type="text/javascript" src="jquery.js"></script>  
<script type="text/javascript">  
    $.getJSON("http://crossdomain.com/services.php?callback=?",  
    function(result) {  
        for(var i in result) {  
            alert(i+":"+result[i]);//循环输出a:1,b:2,etc.  
        }  
    });  
</script> 

Jquery 客户端 方案二:

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    $.ajax({
        url:"http://crossdomain.com/services.php",
        type:'get',//注意:跨域请求是只能是get请求不能使用post请求
        dataType:'jsonp',
        data:'',
        jsonp:'callback',//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
        jsonpCallback:"success",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
        success:function(result) {
            console.log(result);
        },
        timeout:3000
    });
</script>

Jquery 客户端 方案三:

<script type="text/javascript" src="jquery.js"></script>  
<script type="text/javascript">  
    $.get('http://crossdomain.com/services.php?callback=?', {name: encodeURIComponent('tester')}, function (json) { for(var i in json) alert(i+":"+json[i]); }, 'jsonp');  
</script>

 PHP 服务端:

//服务端返回JSON数据
$arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
$result=json_encode($arr);
//动态执行回调函数
$callback=$_GET['callback'];
echo $callback."($result)";

【策略二】基于iframe实现的跨子域:通过修改document.domain来跨子域

将子域和主域的document.domain设为同一个主域.前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域
主域相同的使用document.domain

【策略三】PHP设置header头来实现跨域

 

//Access-Control-Allow-Origin:指定允许其他域名访问。该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
header('Access-Control-Allow-Origin:*');
//Access-Control-Allow-Methods:响应类型
header('Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS');
//Access-Control-Allow-Headers:响应头设置
header('Access-Control-Allow-Headers:X-Requested-With,Content-Type');
//Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
header('Access-Control-Expose-Headers:Authorization');

 

posted @ 2018-12-22 11:57  佛系-Coder  阅读(4183)  评论(0编辑  收藏  举报