1、什么是同源策略?
同源策略是指浏览器出于安全方面的考虑,只允许页面与本页面相同域下的接口进行数据交互,不同源的数据或脚本在没有明确授权的情况下,不能读写对方资源。
同源要求:同域名、同端口、同协议,三者缺一不可。
2、什么是跨域?列举跨域有几种实现形式
跨域指的是跨过同源策略,实现不同域之间进行数据交互的过程叫跨域。跨域的实现形式主要有JSONP方法、CORS方法、降域和postMessage等。
a、JSONP:依托在html下script可以加载任意域下数据这一特点,将script的src属性设置成欲请求的数据地址,先通过script去加载对应数据并将其作为js在当前页面运行,就实现了跨域操作。然而,对于某些json格式数据直接作为js执行时根本无法将这些数据进行完美解析渲染,所以可以通过在请求url末尾加上一个回调函数,并和后端进行约定好返回数据的格式,将返回的数据(如json数据)构造成能作为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('
404 Not Found
')}else{
res.end(data)
}
})
}
}).listen(8080)
```
后端与前端约定,当请求url的query.callback存在时,就将原来的json数据包装成callback + 原json数据的格式发送给浏览器;而前端则通过如下代码来实现数据请求和解析渲染:
```
$('.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 html += '
}
console.log(html);
$('.news').innerHTML = html;
}
function $(id){
return document.querySelector(id);
}
```
约定的callback为appendHtml,在js中定义好appendHtml函数,将后端返回的包装好的appendHtml({json数据})直接作为函数执行,拼装DOM后渲染到页面上,实现跨域请求数据,并通过js操作该数据展现在当前页面上。
b、CORS方法
CORS(Cross Origin Resourse Sharing),即跨域资源共享,当使用ajax跨域请求数据时,浏览器会给违反同源策略的域加上请求头origin,此时如果不做任何处理,浏览器会拒接接受该请求返回的数据使得数据交互失败,为了跨域实现ajax请求数据,需要在服务器的返回结果中加上:Access-Control-Allow-Origin:(发请求的域名)来提醒浏览器本数据允许该域请求,从而克服同源策略,获取到数据。例如下面例子:
index.html
```
$('.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 html += '
}
$('.news').innerHTML = html
}
function $(selector){
return document.querySelector(selector)
}
```
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/plain; charset = utf-8')
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('
404 Not Found
')}else{
res.end(data)
}
})
}
}).listen(8080)
```
在本地启动服务器,通过浏览器访问localhost:8080/index.html点击button按钮去跨域请求http://127.0.0.1:8080域下getNews数据,正常情况下,浏览器会在同源策略限制下无法请求到数据,这里我们在服务器返回的数据响应头中加上Access-Control-Allow-Origin:http://localhost:8080,将http://localhost:8080设置允许获取getNews,即可跨域请求到该数据。
c、降域
对于后缀相同的两个不同域之间(如:同一个页面上两个iframe a.jrg.com和b.jrg.com),正常情况下两个iframe之间不能数据交互,但如果在对页面的两个iframe进行降域(document.domain = "jrg.com"),则可在两个frame之间进行数据交互,即通过降域实现跨域。