什么是同源策略
同源策略
- 浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
- 本域值得是?
- 同协议:如都是http或者https
- 同域名:如都是http://baidu.com/a和http://baidu.com/b
- 同端口:如都是80端口
举个例子 -
http://baidu.com/a/b.js和http://baidu.com/index.php(同源)
不同源的例子 - http://baidu.com/main.js和http://baidu.com/a.php(协议不同)
- http://baidu.com/main.js和http://google.com/a.php(域名不同,域名必须完全相同才可以)
-
http://baidu.com/main.js和http://baidu.com:8080/a.php(端口不同,第一个端口是80)
需要注意的是,对于当前页面来说,页面存放的JS文件的域不重要,重要的是加载该JS页面所在的什么域
什么是跨域,列举跨域的几种实现形式
跨域同源策略是由Netscape提出的著名安全策略,是浏览器最核心、基本的安全功能,它限制了一个源(origin)中加载文本或者脚本与来自其他源(origin)中资源的交互方式,所谓的同源就是指协议、域名、端口相同。当浏览器执行一个脚本时会检查是否同源,只有同源的脚本才会执行,如果不同源即为跨域
跨域的几种方式
- JSONP
- 最常见的一种跨域方式,其背后原理就是利用了script标签不受同源策略的限制,在页面中动态插入了script,script标签的src属性就是后端api接口的地址,并且以get的方式将前端回调处理函数名称告诉后端,后端在响应请求时会将回调返还,并且将数据以参数的形式传递回去。
- CORS
- Cross-Origin Resource Sharing(跨域资源共享)是一种允许当前域(origin)的资源(比如html/js/web service)被其他域(origin)的脚本请求访问的机制。当使用XMLHttpRequest发送请求时,浏览器如果发现违反了同源策略就会自动加上一个请求头:origin,后端在接受到请求后确定响应后会在Response Headers中加入一个属性:Access-Control-Allow-Origin,值就是发起请求的源地址(http://127.0.0.1:8888),浏览器得到响应会进行判断Access-Control-Allow-Origin的值是否和当前的地址相同,只有匹配成功后才进行响应处理。
- 降域跨域
- 不同域下iframe的操作,当这两个域名都属于同一个基础域名!而且所用的协议,端口都一致的时候,可以使用降域来实现跨域。加上
document.domin=‘共同的域名’
进行降域处理
- postMessage
- 在HTML5中新增了postMessage方法,postMessage可以实现跨文档消息传输(Cross Document Messaging),Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage。该方法可以通过绑定window的message事件来监听发送跨文档消息传输内容。使用postMessage实现跨域的话原理就类似于jsonp,动态插入iframe标签,再从iframe里面拿回数据,私认为用作跨页面通信更加适合
JSONP方法实现跨域
server.js
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')
http.createServer(function(req, res){
var pathObj = url.parse(req.url, true)
switch (pathObj.pathname) {
case '/getNews':
var news = [
"第11日前瞻:中国冲击4金 博尔特再战200米羽球",
"正直播柴飚/洪炜出战 男双力争会师决赛",
"女排将死磕巴西!郎平安排男陪练模仿对方核心"
]
res.setHeader('Content-Type','text/json; charset=utf-8')
if(pathObj.query.callback){
res.end(pathObj.query.callback + '(' + JSON.stringify(news) + ')')
}else{
res.end(JSON.stringify(news))
}
break;
default:
fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
if(e){
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
}else{
res.end(data)
}
})
}
}).listen(8080)
index.html
<!DOCTYPE html>
<html>
<body>
<div class="container">
<ul class="news">
</ul>
<button class="show">show news</button>
</div>
<script>
$('.show').addEventListener('click', function(){
var script = document.createElement('script');
script.src = 'http://127.0.0.1:8080/getNews?callback=appendHtml';
document.head.appendChild(script);
document.head.removeChild(script);
})
function appendHtml(news){
var html = '';
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>';
}
console.log(html);
$('.news').innerHTML = html;
}
function $(id){
return document.querySelector(id);
}
</script>
</body>
</html>
JSONP通过script标签加载数据的方式区获取数据当作JS代码来执行,提前在页面上声明了一个函数appendHtml,并将该函数名拼接至url后面变为?callback=appendHtml
传入后台,后台解析到函数名后,在原始数据上包裹上这个appendHtml函数名,发送给前端,前端再次进行处理原始数据展示至页面,这样就实现了跨域请求,当然前提是服务器端有对应的接口。
过程见下列图片
![](https://img.haomeiwen.com/i4469078/9ba0391a48b5f1db.png)
![](https://img.haomeiwen.com/i4469078/7bc760c3082f10b6.png)
![](https://img.haomeiwen.com/i4469078/56689db2d750d265.png)
CORS方法实现跨域
server.js
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')
http.createServer(function(req, res){
var pathObj = url.parse(req.url, true)
switch (pathObj.pathname) {
case '/getNews':
var news = [
"第11日前瞻:中国冲击4金 博尔特再战200米羽球",
"正直播柴飚/洪炜出战 男双力争会师决赛",
"女排将死磕巴西!郎平安排男陪练模仿对方核心"
]
res.setHeader('Access-Control-Allow-Origin','http://localhost:8080')
//res.setHeader('Access-Control-Allow-Origin','*')
res.end(JSON.stringify(news))
break;
default:
fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
if(e){
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
}else{
res.end(data)
}
})
}
}).listen(8080)
index.html
<!DOCTYPE html>
<html>
<body>
<div class="container">
<ul class="news">
</ul>
<button class="show">show news</button>
</div>
<script>
$('.show').addEventListener('click', function(){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8080/getNews', true)
xhr.send()
xhr.onload = function(){
appendHtml(JSON.parse(xhr.responseText))
}
})
function appendHtml(news){
var html = ''
for( var i=0; i<news.length; i++){
html += '<li>' + news[i] + '</li>'
}
$('.news').innerHTML = html
}
function $(selector){
return document.querySelector(selector)
}
</script>
</body>
</html>
当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。和ajax请求非常相似
下面我们给出两个例子
-
成功的例子
而只有当在服务器端的设置可接收请求的头部与请求来源的url一致时,才可生效,数据才能有效地被传输过来,被浏览器所解析
22.png
-
失败的例子
当我们将server.js
文件里的res.setHeader('Access-Control-Allow-Origin','http://localhost:8080')
端口号改为8099时,再次点击就得不到数据了
11.png
网友评论