1. 什么是同源策略
- 同源指的是网页的协议、域名和端口都相同,不同源的客户端脚本在没明确授权的情况下,不能读写对方的资源。
- 同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
- 随着互联网的发展,现主要有三种行为受到同源策略的限制:
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得。
- AJAX 请求不能发送。
URL | 说明 | 是否允许通信 |
---|---|---|
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
|
同一域名,不同二级域名(同上) | 不允许 |
http://www.cnblogs.com/a.js http://www.a.com/b.js
|
不同域名 | 不允许 |
2. 什么是跨域,跨域有几种实现形式?
- 跨域:为了获取不同源网页上的图片、脚本等资源,我们就需要跨域了。
- 跨域的方式
- JSONP
- CORS
- WebSocket
- postMessage
- window.name
- document.domain
3. JSONP 的原理是什么?
- JSONP即 JSON with padding(填充式JSON或参数式JSON),是被包含在函数调用中的JSON,如
callback({ "name": "xiaoming"})
。 - JSONP是通过动态 <script> 元素来使用的,使用时可为 src 属性制定一个跨域URL,<script> 与 <img> 标签类似,都具有不受限制的从其它域加载资源的能力。因为JSONP是有效的 JavaScript 代码,在请求完成后,即JSONP响应加载到页面中以后,就会马上执行。
- JSONP分两部分组成:回调函数和数据。回调函数是当响应到来时,应该在页面调用的函数,回调函数的名字一般是在请求中指定的;而数据就是传入回调函数中的JSON数据。如:
http://www.a.com/?callback=handleResponse
4. CORS是什么?
- CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。CORS背后的基本思想,就是使用自定义的HTTTP头部让浏览器与服务器进行沟通,从而决定响应是成功还是失败。CORS需要浏览器和服务器同时支持,支持现代浏览器,IE支持10以上。
- 整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的 Ajax 通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该响应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。所以 CORS 的表象是让你觉得它与同源的 Ajax 请求没啥区别,代码完全一样。
- 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
5. 跨域的解决方式
JSONP:利用<script>标签没有跨域限制来达到与第三方通讯的目的。
- 创建 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Messages</title>
</head>
<body>
<ul class="messages"></ul>
<script>
var script = document.createElement('script');
script.src = 'http://localhost:8080/getMessages?name=小明&callback=searchMessage';
document.head.appendChild(script);
document.head.removeChild(script);
function searchMessage(person) {
var html = '';
for (var i = 0; i < person.length; i++) {
html += '<li>' + person[i] + '</li>';
}
console.log(html);
$('.messages').innerHTML = html;
}
function $(id) {
return document.querySelector(id);
}
</script>
</html>
- 创建 router.js
router.get('/getMessages', function (req, res) {
var name = req.query.name;
var messages = [];
if (name === '小明') {
messages.push("name: 小明", "age: 23")
} else if (name === '小李') {
messages.push("name: 小李", "age: 20")
} else {
return;
}
var cb = req.query.callback;
if (cb) {
res.send(cb + '(' + JSON.stringify(messages) + ')');
} else {
res.send(messages);
}
})
-
打开本地服务器
本地服务器.png -
打开另外一个端口
JSONP.png
CORS:在HTTP请求里添加特殊的头,允许服务器指定特定的域名可以跨域访问。
- 创建 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Messages</title>
</head>
<body>
<button class="btn">获取信息</button>
<p class="messages"></p>
<script>
var btn = document.querySelector('.btn');
var messages = document.querySelector('.messages');
btn.addEventListener('click', function () {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 304) {
var results = JSON.parse(xhr.responseText);
messages.innerText += '姓名:' + results.name;
}
}
}
xhr.open('GET', 'http://localhost:8080/getMessages?name=小明', true);
xhr.send();
})
</script>
</html>
- 创建 router.js
router.get('/getMessages', function (req, res) {
res.header('Access-Control-Allow-Origin', '*');
var name = req.query.name;
var data = {};
if (name === '小明') {
data = {name: "小明"}
} else if (name === '小李') {
data = {name: "小李"}
} else {
return;
}
res.send(data);
})
-
打开本地服务器
本地服务器.png - 打开另外一个端口
postMessage:允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
- 创建 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>A</title>
</head>
<body>
<input id="inta" type="text" placeholder="aaa">
<p>我是A窗口</p>
<iframe src="http://192.168.0.248:8080/xxx.html" width="300px" height="200px" style="border: 1px dotted"></iframe>
<script type="text/javascript">
var btna = document.getElementById('inta')
btna.oninput = function(){
window.frames[0].postMessage(this.value,'*')
}
window.addEventListener('message',function(e){
btna.value.e.data
})
</script>
</body>
</html>
- 创建 xxx.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>B</title>
</head>
<body>
<input id="intb" type="text" placeholder="bbb">
<p>我是B窗口</p>
<script type="text/javascript">
var btnb = document.getElementById('intb')
btnb.oninput = function(){
window.parent.postMessage(this.value,'*')
}
window.addEventListener('message',function(e){
btnb.value=e.data
})
</script>
</body>
</html>
-
打开另外一个端口
http-server.png -
本地服务器
postMessage.png
网友评论