什么是同源策略
同源策略(same origin policy),1995年同源政策由 Netscape 公司引入瀏覽器。目前,所有瀏覽器都實(shí)行這個(gè)政策瀏覽器出于安全方面的考慮,只允許與本域下的接口進(jìn)行交互。不同源的客戶腳本在沒有明確授權(quán)的情況下,不能讀取對(duì)方的資源。
同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)
本域指的是
- 同協(xié)議:比如都是 http 或者 https
- 同端口:比如都是 80 端口
- 同域名:比如都是
google.com
什么是跨域?跨域有幾種實(shí)現(xiàn)形式
跨域是指通過一定方式繞過瀏覽器同源政策的限制,可以與不同域進(jìn)行交互
目前學(xué)習(xí)到四種實(shí)現(xiàn)形式:
- JSONP
- CORS
- 降域
- postMessage
JSONP 的原理是什么
jsonp 是一種跨域通信的手段,它的原理其實(shí)很簡(jiǎn)單:
- 首先是利用 script 標(biāo)簽的 src 屬性來實(shí)現(xiàn)跨域。
- 通過將前端方法作為參數(shù)傳遞到服務(wù)器端,然后由服務(wù)器端注入?yún)?shù)之后再返回,實(shí)現(xiàn)服務(wù)器端向客戶端通信。
- 由于使用 script 標(biāo)簽的 src 屬性,因此只支持 get 方法
CORS是什么
CORS 是一個(gè) W3C 標(biāo)準(zhǔn),全稱是“跨域資源共享”(Cross-origin resource sharing,它允許瀏覽器向跨源服務(wù)器,發(fā)出 XMLHttpRequest 請(qǐng)求,從而克服了 AJAX 只能同源使用的限制
CORS 需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于 IE10。
整個(gè) CORS 通信過程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來說,CORS 通信與同源的 AJAX 通信沒有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn) AJAX 請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。
因此,實(shí)現(xiàn) CORS 通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了 CORS 接口,就可以跨源通信。
根據(jù)視頻里的講解演示三種以上跨域的解決方式 ,寫成博客
- JSONP
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日前瞻:中國(guó)沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭(zhēng)會(huì)師決賽",
"女排將死磕巴西!郎平安排男陪練模仿對(duì)方核心"
]
res.setHeader('Content-Type','text/json; charset=utf-8')
if(pathObj.query.callback){
res.end(pathObj.query.callback + '(' + JSON.stringify(news) + ')') // 將數(shù)據(jù)處理后返回
}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)
<!DOCTYPE html>
<html>
<body>
<div class="container">
<ul class="news">
</ul>
<button class="show">show news</button>
</div>
<script>
// 通過script標(biāo)簽發(fā)送請(qǐng)求
$('.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);
})
// 將獲取到的數(shù)據(jù)添加到頁面中
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>
</html>
- CORS
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日前瞻:中國(guó)沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭(zhēng)會(huì)師決賽",
"女排將死磕巴西!郎平安排男陪練模仿對(duì)方核心"
]
res.setHeader('Access-Control-Allow-Origin','*') // 設(shè)置響應(yīng)頭中的屬性,允許所有的站點(diǎn)訪問
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)
<!DOCTYPE html>
<html>
<body>
<div class="container">
<ul class="news">
</ul>
<button class="show">show news</button>
</div>
<script>
$('.show').addEventListener('click', function(){
xhr = new XMLHttpRequest(); // 創(chuàng)建 AJAX 請(qǐng)求
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>';
}
console.log(html);
$('.news').innerHTML = html;
}
function $(id){
return document.querySelector(id);
}
</script>
</html>
- postMessage
postMessage 是 HTML5 新增加的一項(xiàng)功能,跨文檔消息傳輸(Cross Document Messaging),目前:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 都支持這項(xiàng)功能,使用起來也特別簡(jiǎn)單-
首先創(chuàng)建 a.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>postMessage</title> </head> <body> <iframe src="http://localhost:8080/b.html" ></iframe> <script> window.onload = function(){ var targetOrigin = "http://localhost:8080"; window.frames[0].postMessage('看到我發(fā)給你的信息沒', targetOrigin); } window.addEventListener('message',function(e){ console.log('a.html接收到信息:',e.data); }); </script> </body> </html> -
創(chuàng)建 b.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>postMessageB</title> </head> <body> <script> window.addEventListener('message',function(e){ if(e.source != window.parent){ return } var data = e.data; console.log("b.html接收到的消息", data); parent.postMessage("我看到你發(fā)的消息了", e.origin) }) </script> </body> </html>
-
在瀏覽器中打開 http://localhos/a.html

跨域成功
參考:MDN