幾種跨域方式的代碼演示
JSONP
優點:
- 它不像XMLHttpRequest 對象實現 Ajax 請求那樣受到同源策略的限制
- 兼容性很好,在古老的瀏覽器也能很好的運行
- 不需要 XMLHttpRequest 或 ActiveX 的支持;并且在請求完畢后可以通過調用 callback 的方式回傳結果。
缺點:
- 它支持 GET 請求而不支持 POST 等其它類型的 HTTP 請求。
- 它只支持跨域 HTTP 請求這種情況,不能解決不同域的兩個頁面或 iframe 之間進行數據通信的問題
- 容易遭受XSS攻擊,因為我們拿到的是對方接口的數據作為js執行,如果得到的是一個很危險js,獲取了用戶信息和cookies,這時執行了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)
<!DOCTYPE html>
<html>
<body>
<div class="container">
<ul class="news">
</ul>
<button class="show">show news</button>
</div>
<script>
// 通過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>
</html>
打開終端,輸入 node server.js ,瀏覽器打開 http://localhost:8080/index.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金 博爾特再戰200米羽球",
"正直播柴飚/洪煒出戰 男雙力爭會師決賽",
"女排將死磕巴西!郎平安排男陪練模仿對方核心"
]
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(); // 創建 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>
啟動終端,執行 node server.js ,瀏覽器打開 http://localhost:8080/index.html ,查看效果和網絡請求
postMessage
HTML5為了解決這個問題,引入了一個全新的API:跨文檔通信 API(Cross-document messaging)。
這個API為window對象新增了一個window.postMessage方法,允許跨窗口通信,不論這兩個窗口是否同源。
舉例來說,父窗口http://a.jrg.com向子窗口http://b.jrg.com發消息,調用postMessage方法可以了。
postMessage方法的第一個參數是具體的信息內容,第二個參數是接收消息的窗口的源(origin),即"協議 + 域名 + 端口"。也可以設為*,表示不限制域名,向所有窗口發送
- 首先創建 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('看到我發給你的信息沒', targetOrigin);
}
window.addEventListener('message',function(e){
console.log('a.html接收到信息:',e.data);
});
</script>
</body>
</html>
- 創建 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("我看到你發的消息了", e.origin)
})
</script>
</body>
</html>
- 用http-server啟動靜態服務器,在瀏覽器中打開 http://localhos/a.html, 即可看到跨域成功