-
什么是同源策略
同源策略是指浏览器处于安全方面的考虑只允许本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读取对方的资源。
其中同源是指:
- 协议相同,比如http://lalala.com
和https://lalala.com
不属于同源
- 域名相同,比如http://b.lalala.com
和http://a.lalala.com
不属于同源
- 端口相同,比如http://lalala.com:8082
和http://lalala.com
不属于同源
-
什么是跨域?跨域有几种实现形式
跨域是指不同域之间的接口进行交互;
常见的跨域解决方式有如下几种:
- ### JSONP
JSONP是JSON with Padding的简写,是应用JSON的一种方法,JSONP看起来 与JSON差不多,只不过是被包含在回调函数中的JSON。JSONP由两部分组成,回调函数和JSON数据,回调函数是当响应到来时应该在页面中调用的函数(这个函数会在页面中提前定义好)。所以JSONP的原理是利用<script>
标签可以不受限制地从其他域加载资源的能力动态创建<script>
标签,然后在这个标签中向指定url请求JSONP数据,当数据被服务端传回页面时,回调函数把JSON数据传入并执行,从而达到从其他域直接访问响应文本的目的。例如:
//事件处理函数,当需要去访问其他域的文本时触发 function eventHandler() { var script = document.createElement('script'); script.src = 'http://otherDomain.com/json/?callback=JSONHandler' document.body.appendChild(script); } //回调函数,当服务端传回类似'JSONHandler' + '(' + json ')'的数据时调用 function JSONHandler(json) {}
下面是一个简单通过JSONP实现的猜数例子:
客户端代码:
<!doctype html> <html> <head> </head> <body> <div id='ctn'> <input type="input" id="number" placeholder="1到100的整数" > <br> <button id="guess">猜吧</button> </div> <script> function $(str) { return document.querySelector(str); } var input = $('#number'); var guess = $('#guess'); //事件处理函数 guess.addEventListener( 'click', function() { var guessNumber = parseInt(input.value); if(isNaN(guessNumber)) { alert('老铁,输个数字过来好吗');return;} var script = document.createElement('script'); script.src = 'http://localhost:8080/guessNumber?callback=xxx&number=' + guessNumber; document.body.appendChild(script); }) //回调函数 function xxx(json) { div = document.createElement('div'); div.innerText = '你猜的数字是:' + parseInt(input.value) + ',' + json[parseInt(input.value)]; ctn.appendChild(div); } </script> </body> </html>
服务端代码:
var theNumber = 77; app.get('/guessNumber', function(req, res){ var data = {}; var guessNumber = parseInt(req.query.number); if(guessNumber > theNumber) { data[guessNumber] = '大了'; } else if(guessNumber < theNumber) { data[guessNumber] = '小了'; } else { data[guessNumber] = '中了'; } //返回JSONP var cb = req.query.callback; console.log(cb); if(cb) { let tmp = cb + '('+ JSON.stringify(data) +')' console.log(tmp); res.send(tmp); } else { res.send(data); } })
下图为本地开启server-mock的效果图:
-
CROS
CROS(Cross-Origin Resource Sharing,跨域资源共享)是W3C定义的一个跨域资源共享规范,规定了在必须访问跨域西原始浏览器与服务器应该如何沟通。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
比如一个简单请求,它没有自定义头部,在发送之前需要给它附加一个额外的`Origin`头部,其中包含请求页面的源信息(协议、域名、端口),以便服务器根据这个头部信息来决定是否给予响应;如果服务器认为该请求可以接受,则在响应报文的首部中添加`Access-Control-Allow-Origin`的头,其值与请求报文中`Origin`头的值一致,或者为`*`表示接受所有域的请求。这里的`Origin`头的发送与是否跨域无关。
其中简单请求的定义如下:
>只要同时满足以下两大条件,就属于简单请求
1. 请求方法是以下三种方法之一:
- HEAD
- GET
- POST
2. HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
其中Content-Type:只限于三个值application/x-www-form-urlencoded、 multipart/form-data、text/plain
若是一个非简单请求(相对简单请求而言),则在正式发送请求报文之前需要通过`OPTIONS`方法发送一个预检报文,报文首部有`Access-Control-request-method`头和`Access-Control-request-Headers`头,用以告知服务器实际请求所使用的HTTP方法和携带的自定义首部,然后服务器根据这些值判断是否接受该请求;然后返回响应报文,在响应报文中添加`Access-Control-Allow-Methods`头和`Access-Control-Allow-Headers`头作为请求报文中对应头的回复。
-
降域
// 降域方式
// 修改document.domain的方法只适用于不同子域
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
document.domain = 'example.com';//设置成主域
function test(){
alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
}
</script>
// 子窗口
<script type="text/javascript">
document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>
-
postMessage
window.postMessage(message,targetOrigin)
方法是html5新引进的特性,可以使用它来向其它的window
对象发送消息,无论这个window
对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage
方法。
调用`postMessage`方法的`window`对象是指要接收消息的那一个`window`对象,该方法的第一个参数`message`为要发送的消息,类型只能为字符串;第二个参数`targetOrigin`用来限定接收消息的那个`window`对象所在的域,如果不想限定域,可以使用通配符 * 。需要接收消息的`window`对象,可是通过监听自身的`message`事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。
更多请参看:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
http://zqdevres.qiniucdn.com/data/20160412110843/index.html
http://www.cnblogs.com/2050/p/3191744.html