概念1:同源策略
同源策略串结,Same-origin policy蒿柳,瀏覽器處于安全考慮阵难,只允許與本域下的接口交互岳枷。不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源呜叫。
概念2:本域
- 相同的協(xié)議
- 相同的域名
- 相同的端口
跨域
因為瀏覽器的同源策略空繁,如果不加特殊處理,在一個頁面中向不同域的接口發(fā)送請求是不會得到數(shù)據(jù)的朱庆,這種向不同域的接口發(fā)送請求的行為就是跨域盛泡。
實現(xiàn)跨域
方式
- JSONP
- CORS
- 降域
- postMessage
JSONP
原理:
html中的script標(biāo)簽可以引入其他域下的js,利用這個特性可以達(dá)到跨域娱颊。
通過script.src指定域名發(fā)送請求
后端經(jīng)過處理返回特定的字符串(函數(shù)格式)
返回的數(shù)據(jù)作為參數(shù)傳入一個數(shù)據(jù)處理函數(shù)
這時執(zhí)行JS中的數(shù)據(jù)處理函數(shù)就可以實現(xiàn)數(shù)據(jù)交換傲诵,達(dá)到跨域的目的凯砍。
代碼演示:
<!DOCTYPE html>
<html>
<head>
<meta chartset="utf-8">
<title>跨域-jsonp</title>
</head>
<body>
<button>點我</button>
<ul class="news"></ul>
<script>
var btn = document.querySelector("button")
btn.addEvevtListener('click',function(){
var script = document.createElement('script')
script.src = 'http://localhost:8080/getNews?callback=appendHtml'
document.head.appendChild(script)
document.head.removeChild(script)
})
function appendHtml(news){
var html = ''
html += '<li>' + news + '</li>'
var addnews = document.querySelector('.news')
addnews.innerHTML = html
}
</script>
</body>
</html>
-----------------------------------------------
使用mock-server模擬后端
router.get('/getnews',function(req,res){
var news = ["test1","test2","test3","test4","test5"]
var data = []
var index = parseInt(math.random()*news.length)
data.push(news[index])
var cb = req.query.callback
if(cb){
res.send(cb + '(' + JSON.stringify(data) + ')') //在后端將返回的數(shù)據(jù)處理成函數(shù)格式返回到JS后執(zhí)行,達(dá)到跨域目的
}else{ res.send(data)}
})
效果
CORS
Cross-Origin Resource Sharing拴竹,跨域資源共享悟衩,是一種ajax跨域請求資源的方法。
原理
當(dāng)使用XMLHttpRequest發(fā)送請求時栓拜,當(dāng)瀏覽器發(fā)現(xiàn)請求不符合同源策略時座泳,瀏覽器會給該請求加一個請求頭origin,值為當(dāng)前頁面的域名,通過后端處理幕与,返回結(jié)果中加入一個響應(yīng)頭Access-Control-Allow-Origin挑势,如果值也為origin或者"*",則可以拿到數(shù)據(jù)啦鸣,實現(xiàn)跨域薛耻。
代碼演示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨域-cors</title>
</head>
<body>
<button class="btn">點我</button>
<ul class="news"></ul>
<script>
var btn = document.querySelector('.btn')
btn.addEventListener("click",function(){
var xhr = new XMLHttpRequest()
xhr.open('get','http://b.jirengu.com:8080/getNews',true)
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
appendHtml(JSON.parse(xhr.responseText))
}
}
window.xhr = xhr
})
function appendHtml(news){
var addnews = ducument.querySelector('.news')
var html = ''
html += '<li>' + news + '</li>'
addnews.innerHTML= html
}
</script>
</body>
</html>
-------------------------------------------------------------------------
使用mock-server模擬后端
router.get('/getNews',function(req,res){
var news = ['test1','test2','test3','test4','test5','test6','test7']
var data = []
var index = parseInt(Math.random()*news.length)
data.push(news[index])
res.header("Access-Control-Allow-Origin","http://a.jrg.com:8080")
// res.header("Access-Control-Allow-Origin","*")
res.send(data)
})
效果
降域
對于頁面中使用iframe嵌套另外的網(wǎng)站時,如果符合同源策略赏陵,就可以通過window.frames[].document
操作對應(yīng)iframe里的網(wǎng)站,如果不符合饲漾,則不能相互訪問蝙搔,但是如果這些網(wǎng)站有著相同的主網(wǎng)站,則可以通過降域?qū)崿F(xiàn)跨域考传。例如:a.test.com:8080和b.test.com:8080的主域名為test.com:8080
原理
在script標(biāo)簽里寫上document.domain = "主域名"
吃型,就可以實現(xiàn)降域,
然后就可以使用window.frames[].document
操作對應(yīng)iframe里的網(wǎng)站僚楞,實現(xiàn)跨域勤晚。
代碼演示
創(chuàng)建a.html文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨域-降域-a</title>
</head>
<body>
<div class="ct">
<div class="main">
<input type="text" placeholder="http://a.jirengu.com:8080/a.html">
</div>
<iframe src="http://b.jirengu.com:8080/b.html"></iframe>
</div>
<script>
document.querySelector('.main input').addEventListener('input',function(){
windows.frames[0].document.querySelector('input').value = this.value
})
document.domain = "jirengu.com"
</script>
</body>
</html>
----------------------------------------------------------------
創(chuàng)建b.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b.html</title>
</head>
<body>
<input type="text" placeholder="http://b.jirengu.com:8080/b.html">
<script>
document.querySelector('input').addEventListener('input',function(){
windows.parent.document.querySelector('input').value = this.value
})
document.domain = "jirengu.com"
</script>
</body>
</html>
效果
在前面已修改了hosts文件,將測試用的a.jirengu.com和b.jirengu.com寫入到hosts中對應(yīng)127.0.0.1泉褐,然后使用server-mock模擬后端赐写。
postMessage
postMessage()方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實現(xiàn)跨文本檔膜赃、多窗口挺邀、跨域消息傳遞。
postMessage(data,origin)方法接受兩個參數(shù)
data:要傳遞的數(shù)據(jù)
origin:可以設(shè)置目標(biāo)窗口的url跳座,只包括協(xié)議端铛、域名、端口疲眷。也可以設(shè)置為"*"
,表示傳遞給任意窗口
原理
postMessage可向任意窗口發(fā)送數(shù)據(jù)禾蚕,由目標(biāo)窗口選擇接受數(shù)據(jù)。
通過postMessage()發(fā)送數(shù)據(jù)狂丝,然后再寫一個監(jiān)聽函數(shù)就可以實現(xiàn)跨域操作换淆。
代碼演示
創(chuàng)建a.html文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨域-降域-a</title>
</head>
<body>
<div class="ct">
<div class="main">
<input type="text" placeholder="http://a.jirengu.com:8080/a.html">
</div>
<iframe src="http://b.jirengu.com:8080/b.html"></iframe>
</div>
<script>
var input = document.querySelector('.main input')
input.addEventListener('input',function(){
window.frames[0].postMessage(this.value,"*")
})
window.addEventListener('message',function(e){
input.value = e.data
})
</script>
</body>
</html>
----------------------------------------------------------------
創(chuàng)建b.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b.html</title>
</head>
<body>
<input type="text" placeholder="http://b.jirengu.com:8080/b.html">
<script>
var input = document.querySelector('input')
input.addEventListener('input',function(){
window.parent.postMessage(this.value,'http://a.jirengu.com:8080')
})
window.addEventListener('message',function(e){
input.value = e.data
})
</script>
</body>
</html>
效果
這個demo演示效果和降域一樣哗总。
以上。