在跨域安全性方面,有多个地方会有限制,主要是XMLHttpRequest对象的跨域限制和iFrame的跨域限制,下面我们分别来看一下。

Ajax跨域(CORS)

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

以PHP服务端为例

如果一个请求允许http://www.example.com的域请求的话,可以在PHP中这么写:

header("Access-Control-Allow-Origin:http://www.example.com");

如果有多个允许跨域访问的地址,可以添加多条或使用“,”号进行分隔,如果希望所有来源的地址都可以访问当前的页面,可以如下:

header("Access-Control-Allow-Origin:*");

同时,也可以控制请求的方法,如下是允许GET和POST两种请求方法:

header("Access-Control-Allow-Method:POST,GET");

IE中,要跨域需要使用到XDomainRequest的对象,我们这里就不展开来说了,而在其它浏览器中,使用XMLHttpRequest对象即可,并没有不一样的地方。

一个需要注意的地方

最近在公司开发的过程中,遇见的情况是PHP已经添加了header("Access-Control-Allow-Origin:*");代码,但是客户端请求时,仍然报错,最终查出的bug是,包含的其它PHP中,也添加了相同的代码,导致服务端返回时,在Chrome的Network页面中,发现有两条一样的头部数据,去掉一条即可。

CORS跨域之前的跨域方法

在CORS标准出现之前,XHR对象是不能跨域请求的,不过开发人员凭借自己的聪明才智,绕过了XHR对象,创造了另外几种可以跨域请求的方式,我们下面开简单的看看。

图像Ping

前端里面图片元素没有跨域的限制,所以我们可以通过模拟请求一个图片的方法,向服务端发送数据,服务端对应的页面可以返回一个简单的图片数据或者什么数据都不返回(客户端得到204状态)。

1 var img = new Image();
2 img.onload = img.onerror = function () {
3 console.log("Done");
4 }
5 img.src = "http://www.example.com/test.php?name=LiLei&age=28";

缺点是可以得到请求成功和失败的回调但是得不到服务端返回的数据,除非将数据放入图片返回。

统计在线广告浏览量等不需要返回数据的情况下通常使用该方式。

JSONP

即JSON with padding的简写,简单来说:就是通过添加一个script标签,通过创建该标签的src地址来传递参数,而服务端返回JS代码的内容,JS代码回调一个页面中已经存在的JS方法,同时将需要给到客户端的信息作为参数传递即可。这样就可以绕过XHR对象实现跨域请求并得到服务端返回的数据。

1 function handleResponse (response) {
2 console.log("name: " + response.name + ", age: " + response.age);
3 }
4
5 var script = document.createElement("script");
6 script.src = "http://www.example.com/test.php?name=LiLei&age=28";
7 document.body.insertBefore(script, document.body.firstChild);

当前代码中的handleResponse方法即服务端会回调的方法。

handleResponse({"name":"Han Meimei", "age":27});

服务端返回上面的文本后,由于是添加的script脚本,所以会调用到handleResponse方法并得到服务端的数据。

JSONP缺点

  1. 访问的其他域如果不安全,可能会返回一些有害的JS代码到当前页面进行执行;
  2. 难以确定请求失败的响应,需要用户自己实现一个超时计时器。

iFrame跨域

JavaScript出于安全方面的考虑,不允许iFrame跨域访问和调用其他页面的对象。

试想一下,如果我们做了一个钓鱼网站,使用一个iFrame引入了XX银行的首页,把自己伪装成该银行首页,此时如果我们可以跨域调用和修改XX银行的所有数据,也可以通过修改和注入JS代码,后果就是:如果有人登录了我们的假网站,我们就可以通过给这个iFrame添加我们自己的JS代码来轻松获得这个人的帐号和密码信息。

所以,iFrame不允许跨域访问是基于安全的考虑,也是必要的一个安全限制。

我们看下,具体的跨域限制:

  • http://www.a.com/a.js http://www.a.com/b.js 同一域名下 允许
  • http://www.a.com/lab/a.js http://www.a.com/script/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 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
  • http://www.cnblogs.com/a.js http://www.a.com/b.js 不同域名 不允许

但是不可否认的是,在某些情况下,我们还是希望不同域的页面之间可以相互通信(注意这里不一定要相互可以调用修改)。下面我们来看看如何实现跨域的消息通信。

document.domain

通过修改多个框架domain属性为同样的值,可以突破跨域的限制,使多个页面之间可以互相访问到。

但是domain属性的修改有下面两个限制。

只能修改子域为主域,不能修改为其它域

域example.com嵌入了域p2p.example.com的页面,通过修改p2p.example.com的domain即可实现双方互相访问和修改,如同没有跨域一样,但是要注意不能改为其它域:

1 document.domain = "example.com"; // 成功
2 document.domain = "baidu.com"; // 报错

不能将主域修改为子域

如下,位于p2p.example.com的页面:

1 document.domain = "example.com"; // 成功
2 document.domain = "p2p.example.com"; // 报错

因为已经设置为主域了,再次设置会子域会报错。

使用postMessage

跨文档消息传递(cross-document messaging),简称XDM,在H5中该功能可以用来向iFrame嵌套的页面和嵌套自己的页面相互发送消息,也可以向当前页面弹出的窗口相互传递消息。

通过XDM我们可以安全的实现页面之间的跨域消息传递。

XDM得核心方法是postMessage,postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

postMessage(data,origin)方法接受两个参数:

  1. data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。
  2. origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口。

而在发送了消息之后,符合条件(iFrame嵌套页面或弹出窗口,且符合postMessage的origin参数的域)的其他页面的window对象会收到该消息,作为“message”事件抛出该消息,对应的event对象有如下主要属性:

  1. data:顾名思义,是传递来的message;
  2. source:发送消息的窗口对象;
  3. origin:发送消息窗口的源(协议+主机+端口号)。

下面我们看一个例子:

A.html

 1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>A</title>
6 <body>
7 <p>A</p>
8 <input type="button" value="发送消息到frameB并得到frameB的回应" onclick="sendMsg()">
9 <iframe id="frameB" src="./B.html" style="width: 90%;"></iframe>
10 <script type="text/javascript">
11 window.addEventListener("message", function (event) {
12 console.log("A.html接收到消息:" + event.data);
13 });
14
15 function sendMsg () {
16 var frameB = document.getElementById("frameB");
17 frameB.contentWindow.postMessage("Hello I am Li Lei", "*");
18 }
19 </script>
20 </body>
21 </html>

B.html

 1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>B</title>
6 </head>
7 <body bgcolor="#ff0000">
8 <p>B</p>
9 <script type="text/javascript">
10 window.addEventListener("message", function (event) {
11 console.log("B.html接收到消息:" + event.data);
12 //向发送消息的window回送消息
13 event.source.postMessage("Hi, I am Han Meimei!", "*");
14 });
15 </script>
16 </body>
17 </html>

需要注意,window对象发送的消息只有自身可以接收到message消息。

图片crossOrigin属性

我们在请求其它域下的图片时,可以显示出来,但是当调用toBlob(),toDataURL()getImageData()等方法时会抛出安全错误,这是由于浏览器的安全策略导致的。

第一步,服务端配置图片类型资源的跨域范围权限,如Apache服务器可以如下配置:

1 <IfModule mod_setenvif.c>
2 <IfModule mod_headers.c>
3 <FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
4 SetEnvIf Origin ":" IS_CORS
5 Header set Access-Control-Allow-Origin "*" env=IS_CORS
6 </FilesMatch>
7 </IfModule>
8 </IfModule>

第二步,在浏览器端可以设定Image对象或img标签的crossOrigin属性为"Anonymous"即可。

HTML5学习笔记:跨域的更多相关文章

  1. jw player学习笔记----跨域请求

    需求来源:播放器皮肤文件请求不到,被限制了. 参考官网解决方案: http://www.longtailvideo.com/support/jw-player/28844/crossdomain-fi ...

  2. AJAX学习笔记——跨域

    跨域 一个域名地址的组成 http:// www abc.com : 8080 / scripts/jquery.js 协议 子域名 主域名 端口号 请求资源地址 端口号:一般来说域名端口号是80,如 ...

  3. html5学习笔记一

    HTML5学习笔记 <video>标记:定义视频,Ogg.MPEG4.WebM三种格式 <video src=”movie.ogg”  controls=”controls”> ...

  4. [转]html5: postMessage解决跨域和跨页面通信的问题

    [转]html5: postMessage解决跨域和跨页面通信的问题 平时做web开发的时候关于消息传递,除了客户端与服务器传值,还有几个经常会遇到的问题: 多窗口之间消息传递(newWin = wi ...

  5. vue.js学习之 跨域请求代理与axios传参

    vue.js学习之 跨域请求代理与axios传参 一:跨域请求代理 1:打开config/index.js module.exports{ dev: { } } 在这里面找到proxyTable{}, ...

  6. Html5学习笔记1 元素 标签 属性

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 【Java Web开发学习】跨域请求

    [Java Web开发学习]跨域请求 ================================================= 1.使用jsonp ===================== ...

  8. HTML5学习笔记之表格标签

    HTML5学习笔记之表格标签 其他HTML5相关文章 HTML5学习笔记之HTML5基本介绍 HTML5学习笔记之基础标签 HTML5学习笔记之表格标签 HTML5学习笔记之表单标签 HTML5学习笔 ...

  9. HTML5学习笔记(二十八):跨域

    在跨域安全性方面,有多个地方会有限制,主要是XMLHttpRequest对象的跨域限制和iFrame的跨域限制,下面我们分别来看一下. Ajax跨域(CORS) CORS是一个W3C标准,全称是&qu ...

随机推荐

  1. C#用Oracle.DataAccess中连接Oracle要注意版本问题!

    客户端Oracle.DataAccess.dll与服务器版本不一致时,如下修改:1.在客户端Web.config中,增加如下配置:<runtime> <assemblyBinding ...

  2. Java编程的逻辑 (10) - 强大的循环

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  3. linux编译内核make menuconfig报错Unable to find the ncurses libraries解决办法

    在 linux 编译内核时 make menuconfig 报了下面的错误. *** Unable to find the ncurses libraries or the *** required ...

  4. HDU 4348 To the moon(主席树区间修改)

    题意 给你一个区间,支持如下操作: 在一段区间内加上一个值,并生成一个历史版本 查询某个版本下一段区间内的和 回到一个历史版本上并舍弃之后的版本 做法 这就是主席树区间修改裸题啦QwQ 上一篇博客我讲 ...

  5. EntityFramework 系列:实体类配置-根据依赖配置关系和关联

    EF实体类的配置可以使用数据注释或Fluent API两种方式配置,Fluent API配置的关键在于搞清实体类的依赖关系,按此方法配置,快速高效合理.为了方便理解,我们使用简化的实体A和B以及A.B ...

  6. SSH免密登录机制

     SSH免密登录机制:(见下图) 1.A先使用ssh-keygen生成一对公钥和私钥:ssh-keygen 2.将A的公钥复制给B一份,并且将其追加到B的授权文件中:ssh-copy-id B 3.接 ...

  7. mysql排序数据

    一:order by的普通使用 1.介绍 当使用SELECT语句查询表中的数据时,结果集不按任何顺序进行排序.要对结果集进行排序,请使用ORDER BY子句. ORDER BY子句允许: 对单个列或多 ...

  8. Odoo访问权限(一)

    Odoo访问权限(一) 四个ODOO权限管理层次 一. Odoo 菜单级别: 即,不属于指定菜单所包含组的用户看不到该菜单.不安全,只是隐藏菜单,若用户知道菜单ID,仍然可以通过指定URL访问 二. ...

  9. 卡尔曼滤波(kalman)相关理论以及与HMM、最小二乘法关系

    一.什么是卡尔曼滤波 在雷达目标跟踪中,通常会用到Kalman滤波来形成航迹,以前没有学过机器学习相关知识,学习Kalman时,总感觉公式看完就忘,而且很多东西云里雾里并不能深入理解,最后也就直接套那 ...

  10. 关于dubbo服务的xml配置文件报错的问题

    在配置dubbo服务的过程中,经常会遇到虽然程序能够跑起来,但是配置文件一堆红叉,虽然不影响功能,但是确实很让人恶心. 报错信息如下: Multiple annotations found at th ...