什么是同源策略
同源策略(same origin policy),1995年同源政策由 Netscape 公司引入瀏覽器渴庆。目前,所有瀏覽器都實行這個政策瀏覽器出于安全方面的考慮,只允許與本域下的接口進行交互。不同源的客戶腳本在沒有明確授權的情況下诫龙,不能讀取對方的資源。
同源政策的目的鲫咽,是為了保證用戶信息的安全签赃,防止惡意的網(wǎng)站竊取數(shù)據(jù)
本域指的是
- 同協(xié)議:比如都是 http 或者 https
- 同端口:比如都是 80 端口
- 同域名:比如都是
google.com
什么是跨域?跨域有幾種實現(xiàn)形式
跨域是指通過一定方式繞過瀏覽器同源政策的限制分尸,可以與不同域進行交互
目前學習到四種實現(xiàn)形式:
- JSONP
- CORS
- 降域
- postMessage
JSONP 的原理是什么
jsonp 是一種跨域通信的手段锦聊,它的原理其實很簡單:
- 首先是利用 script 標簽的 src 屬性來實現(xiàn)跨域。
- 通過將前端方法作為參數(shù)傳遞到服務器端箩绍,然后由服務器端注入?yún)?shù)之后再返回孔庭,實現(xiàn)服務器端向客戶端通信。
- 由于使用 script 標簽的 src 屬性材蛛,因此只支持 get 方法
CORS是什么
CORS 是一個 W3C 標準圆到,全稱是“跨域資源共享”(Cross-origin resource sharing,它允許瀏覽器向跨源服務器仰税,發(fā)出 XMLHttpRequest 請求构资,從而克服了 AJAX 只能同源使用的限制
CORS 需要瀏覽器和服務器同時支持抽诉。目前陨簇,所有瀏覽器都支持該功能,IE瀏覽器不能低于 IE10迹淌。
整個 CORS 通信過程河绽,都是瀏覽器自動完成,不需要用戶參與唉窃。對于開發(fā)者來說耙饰,CORS 通信與同源的 AJAX 通信沒有差別,代碼完全一樣纹份。瀏覽器一旦發(fā)現(xiàn) AJAX 請求跨源苟跪,就會自動添加一些附加的頭信息廷痘,有時還會多出一次附加的請求,但用戶不會有感覺件已。
因此笋额,實現(xiàn) CORS 通信的關鍵是服務器。只要服務器實現(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日前瞻:中國沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭會師決賽",
"女排將死磕巴西鉴未!郎平安排男陪練模仿對方核心"
]
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標簽發(fā)送請求
$('.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日前瞻:中國沖擊4金 博爾特再戰(zhàn)200米羽球",
"正直播柴飚/洪煒出戰(zhàn) 男雙力爭會師決賽",
"女排將死磕巴西枢冤!郎平安排男陪練模仿對方核心"
]
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)
<!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 請求
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 新增加的一項功能铜秆,跨文檔消息傳輸(Cross Document Messaging)淹真,目前:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 都支持這項功能连茧,使用起來也特別簡單-
首先創(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
postMessage.png
跨域成功
參考:MDN