当前位置:首页 > php > 正文内容

PHP中跨域原理以及解决方案

phpmianshi6年前 (2015-03-29)php858

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不会专门用来做跨域,而是作为消息推送或者聊天等.


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

php项目中从MYSQL更新到MYSQLI

背景因为MYSQL已被弃用,原有一些老的项目大量用到原生mysql_xxx相关的函数,不能预处理和参数绑定,很多拼接的sql有注入风险,如何升级到mysqli或pdo呢因为mysqli是mysql的增...

php中preg_match_all只能匹配100000字节的限制

背景用preg_match_all匹配时,偶尔会匹配失败,只能匹配到一部分符合的数据,代码如下://获取html文本中的a标签,然后获取 标签 <>之间的内容 fun...

PHP中命名空间概述

(PHP 5 >= 5.3.0, PHP 7)什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的...

PHP程序员解决问题能力的六个级别

青铜  var_dump/die打印变量值信息单步调试是最简单粗暴有效的解决问题方法。高级一点的是使用打印日志。白银 会设置各种错误日志的记录和显示,并根据各种错误日志分析错误或者搜索别人的...

PHP内核分析之深入理解字符串(七)

一、字符串的结构struct _zend_string {     zend_refcounted_h gc; &nb...

php中opcache注意事项以及调优

背景从 PHP5.5 开始,Opcache 扩展是核心的一部分,增加了对 PHP 脚本的字节码缓存的支持。对于动态语言(例如 PHP ),字节码缓存可以显著的提高性能,因为它可以确保脚本仅被编译一次。...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。