PHP中跨域原理以及解决方案读这一篇就够了

参考:https://www.phpmianshi.com/?id=88

 

1.为啥出现跨域

在制定Html规则时,为了安全的考虑,一个源的脚本(网页,网站)不能与另一个源的资源进行交互,

所以就引发一个词叫做“同源策略”。

所谓同源(即指在同一个域),就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

 

2.啥是跨域

当协议,主机,和端口号有一个不同时,就是跨域。

 

 

3.解决跨域的方法

对最主要的AJAX跨域来说(也就是平常调接口时):

1)(后端)服务器配置CORS(跨域资源共享)

 

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就>是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。目前,所有浏览器都支持该功能,IE浏览器不能低>于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏>览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

CORS案例:

浏览器在发出CORS请求时会在头信息之中增加一个Origin字段;

后端返回代码中增加三个字段

header(“Access-Control-Allow-Origin”:“”); // 必选 允许所有来源访问
header(“Access-Control-Allow-Credentials”:“true”); //可选 是否允许发送cookie
header(“Access-Control-Allow-Method”:“POST,GET”); //可选 允许访问的方式

 

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。

目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。

但不能实现修改cookie中domain信息,不方便当前域cookie写入,即不能实现登录认证。

 

2)(后端)nginx,反向代理,把跨域改造成同域

3)(前端)将JSON升级成JSONP,,JSONP 的原理很简单,就是利用  < script> 标签没有跨域限制的漏洞。通过 < script>
标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。

JSONP 使用简单且兼容性不错,但是只限于 get 请求。(缺点)

JSONP案例:

两个网站A,和B,其中B通过jsonp接口向外提供职位查询功能,A网站通过该jsonp接口向B发起职位查询数据。

首先创建一个查询表单页面,即search.html

<script>
	var url='https://www.phpmianshi.com/index.php?r=index/jsonp';
	$("#dian").click(function(){
		var zhi=$("#val").val();
		var data={zhi:zhi};//搜索值
		$.get(url,data,function(msg){
			//console.log(msg);
			//alert(msg[0].p_name);
			var html='职位:';
			for (var i in msg) {
				//将接到的jsonp数据进行遍历
				html+='<br /> '+msg[i].p_name;
			};
			$('#list').append(html);
		},'jsonp')//指定数据为jsonp
	})
	//下面的方法也可以 为原生的ajax方法
	/*$("#dian").click(function () {
		var zhi=$("#val").val();
	$.ajax({
	url: url,
	data:'zhi='+zhi,
	dataType: "jsonp",
	jsonpCallback: "aa",
	success: function (msg) {
	//console.log(data)
	$('#list').append('职位:'+msg[0].p_name);
	}
	})
	})*/
	</script>

然后,创建一个接口

//jsonp 接口 查询职位
public function actionJsonp()
{
header("Access-Control-Allow-Origin: *");//同源策略 跨域请求 头设置
header('content-type:text/html;charset=utf8 ');
//获取回调函数名
$jsoncallback = htmlspecialchars($_REQUEST['callback']);//把预定义的字符转换为 HTML 实体。
$zhi = htmlspecialchars($_REQUEST['zhi']);
$arr=yii::$app->db->createCommand("select * from position where p_name like :name",array(':name'=>"%$zhi%"))->queryAll();
$json_data=json_encode($arr);
//输出jsonp格式的数据
echo $jsoncallback . "(" . $json_data . ")";
}

 

4) 对iframe跨域来说:H5提供了postMessage()的方法,可以在父子页面进行通信(加分项)

 

这是由H5提出来的的API,IE8以上支持这个功能。

window.postMessage() 方法可以安全地实现跨源通信。
window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后,向目标窗口派发一个  MessageEvent 消息。

用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

例子:
1.)a.html:(https://domain1.phpmianshi.com/a.html)

<iframe id="iframe" src="https://domain2.phpmianshi.com/b.html" style="display:none;"></iframe><script>       
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // 向domain2传送跨域数据
        iframe.contentWindow.postMessage(JSON.stringify(data), 'https://domain2.phpmianshi.com');
    };

    // 接受domain2返回数据
    window.addEventListener('message', function(e) {
        alert('data from domain2 ---> ' + e.data);
    }, false);</script>

2.)b.html:(https://domain2.phpmianshi.com/b.html)

<script>
    // 接收domain1的数据
    window.addEventListener('message', function(e) {
        alert('data from domain1 ---> ' + e.data);

        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;

            // 处理后再发回domain1
            window.parent.postMessage(JSON.stringify(data), 'https://domain1.phpmianshi.com');
        }
    }, false);</script>


 

 

5.webscoket协议跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
WebSocket不会专门用来做跨域,而是作为消息推送或者聊天等.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章