浅谈前端跨域

1、什么是跨域?

跨域简单的理解就是JavaScript同源策略的限制。是出于安全的考虑,a.com域名下的js不能操做b.com或者c.com域名下的对象。
当协议、子域名、主域名、端口号中任意一个不相同时,都算做不一样域。不一样域之间相互请求资源,就算叫“跨域”。javascript

一个正常的域名地址组成(图片来自网络资源):
图片描述html

注意:跨域不是请求发布出去,请求能够正常发出,服务器也能收到并返回结果,只是结果被浏览器所拦截了。java

附上一张参考图,便于你们深刻理解(图片来自网络资源)
图片描述web

2、什么是同源策略与限制

同源策略限制了从同一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。这是一种保护用户信息,防止恶意身份伪造的一种安全机制。
同源策略限制的内容:ajax

  1. Ajax请求不能正常进行。
  2. Cookie、LocalStoage、indexDB等没法读取。

3.DOM 没法得到。json

不过,有几个标签却能够容许跨域请求资源(能够做为解决跨域的一种方案)。跨域

1.<img src="xxxx" alt="">
2.<link rel="stylesheet" href="xxx">
3.<script src="xxx"></script>

3、处理跨域方法一——JSONP

JSONP是跨域通讯最经常使用的方法,其最大的特色就是简单适用、兼容性好,可用于解决主流浏览器的跨域数据访问的问题。
缺点是仅支持get方法具备局限性。
它的基本思想是,在网页中添加一个<script>标签,像服务器请求JSON数据。它须要服务器端的配合,服务器收到请求后,将数据放在指定名字的回调函数中传回来。
<script type="text/javascript">
    function foo(data) {
        console.log(data.msg);
    }
</script>
<script type="text/javascript" src="http://xxx.com/xx?callback=foo"></script>

注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。浏览器

因为<script>元素请求的脚本,直接做为代码运行。这时,只要浏览器定义了foo函数,该函数就会当即调用。做为参数的JSON数据被视为JavaScript对象,而不是字符串,所以避免了使用JSON.parse的步骤。

jQuery的jsonp形式

JSONP都是GET和异步请求的,不存在其余的请求方式和同步请求,且jQuery默认就会给JSONP的请求清除缓存缓存

$.ajax({
url: "http://xxx/xx",
dataType: "jsonp",
type: "get",//能够省略
jsonpCallback: "fn",//->自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略
jsonp: "jsonp",//->把传递函数名的那个形参callback变为jsonp,可省略
success: function (data) {
    console.log(data);
} });

4、处理跨域方法二——CORS

CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS容许任何类型的请求。缺点是兼容性不如JSONP。安全

CORS要求浏览器(>IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。所以,实现CORS通讯的关键是服务器。只要服务器实现了CORS接口,就能够跨源通讯。
服务器端作的小改动:

header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:POST,GET");

//在服务器端设置同源策略地址

router.get("/userlist",function (req, res,next) {
var user = {
        name: 'Mr.Cao',
        gender: 'male',
        career: 'IT Education'
    };
res.writeHeader(200, {"Access-Control-Allow-Origin": 'http://localhost:63342'});
res.write(JSON.stringify(user));
res.end(); });

在响应头上添加 Access-Control-Allow-Origin 属性,指定同源策略的地址。同源策略默认地址是网页的自己。只要浏览器检测到响应头带上了CORS,而且容许的源包括了本网站,那么就不会拦截请求响应。

5、处理跨域方法三——WebSocket

WebSocket是一种通讯协议,使用ws://(非加密)和wss://(加密)做为协议前缀。该协议不实行同源政策,只要服务器支持,就能够经过它进行跨源通讯。
下面是一个例子,浏览器发出的WebSocket请求的头信息

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪一个域名。

正是由于有了Origin这个字段,因此WebSocket才没有实行同源政策。由于服务器能够根据这个字段,判断是否许可本次通讯。若是该域名在白名单内,服务器就会作出以下回应。

6、处理跨域方法四——跨文档通讯 API/片断识别符/window.name

若是两个网页不一样源,就没法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口没法通讯。

对于彻底不一样源的网站,目前有三种方法,能够解决跨域窗口的通讯问题。

6.1 片断识别符

片断标识符(fragment identifier)指的是,URL的#号后面的部分,好比 http://xxx.com/x.html#fragmen...。若是只是改变片断标识符,页面不会从新刷新。
父窗口能够把信息,写入子窗口的片断标识符。

var src = originURL + '#' + data;
 document.getElementById('myIFrame').src = src;

子窗口经过监听hashchange事件获得通知。

window.onhashchange = checkMessage;    
function checkMessage() {
  var message = window.location.hash;
  // ...
}

6.2 window.name
浏览器窗口有window.name属性。这个属性的最大特色是,不管是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页能够读取它。

父窗口先打开一个子窗口,载入一个不一样源的网页,该网页将信息写入window.name属性。

window.name = data;

接着,子窗口跳回一个与主窗口同域的网址。

location = 'http://parent.url.com/xxx.html';

而后,主窗口就能够读取子窗口的window.name了。

var data = document.getElementById('myFrame').contentWindow.name;

这种方法的优势是,window.name容量很大,能够放置很是长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。

6.3 window.postMessage
上面两种方法都属于破解,HTML5为了解决这个问题,引入了一个全新的API:跨文档通讯 API(Cross-document messaging)。
这个API为window对象新增了一个window.postMessage方法,容许跨窗口通讯,不论这两个窗口是否同源。

举例来讲,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就能够了。

var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');

postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也能够设为*,表示不限制域名,向全部窗口发送。
子窗口向父窗口发送消息的写法相似。

window.opener.postMessage('Nice to see you', 'http://aaa.com');

父窗口和子窗口均可以经过message事件,监听对方的消息。

window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

message事件的事件对象event,提供如下三个属性。

event.source:发送消息的窗口
event.origin: 消息发向的网址
event.data: 消息内容

七 、处理跨域方法五-document.domain

Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。可是,两个网页一级域名相同,只是二级域名不一样,浏览器容许经过设置document.domain共享 Cookie。

举例来讲,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就能够共享Cookie。

document.domain = 'example.com';

如今,A网页经过脚本设置一个 Cookie。

document.cookie = "test1=hello";

B网页就能够读到这个 Cookie。

var allCookie = document.cookie;

注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 没法经过这种方法。

相关文章
相关标签/搜索