跨域指的是訪問(wèn)不同源的url資源赂韵。
瀏覽器出于對(duì)安全方面的考慮族淮,只允許與本域中的接口進(jìn)行交互。不同源的的客戶端在沒(méi)有明確授權(quán)的情況下锐帜,不能讀寫對(duì)方的資源。
本域指的是
1.同協(xié)議 例如都是 http 或者 https
2.同域名 例如都是 baidu.com
3.同端口 例如都是 8080 端口
同源的例子
https://www.baidu.com/a 和 https://www.baidu.com/b
不同源的例子
http://www.baidu.com 和 https://www.baidu.com 協(xié)議不同
http://www.baidu.com 和 http://taobao.com 域名不同
http://www.baidu.com:8081 和 http://www.baidu.com:8080 端口不同
需要注意的是: 對(duì)于當(dāng)前頁(yè)面來(lái)說(shuō)頁(yè)面存放的 JS 文件的域不重要畜号,重要的是加載該 JS 頁(yè)面所在什么域缴阎。瀏覽器允許引用不同域的js,但是js發(fā)起ajax請(qǐng)求時(shí)简软,瀏覽器會(huì)判斷當(dāng)前域药蜻,與請(qǐng)求域是否一致,如果不一致替饿,會(huì)拒絕接收請(qǐng)求域返回的數(shù)據(jù)语泽。
如何跨域?
1.JSONP
1.1 首先在瀏覽器腳本中定義一個(gè)callBack函數(shù)
1.2 創(chuàng)建一個(gè)script腳本视卢,并將script的src寫為需要訪問(wèn)的接口地址踱卵,
同時(shí)帶上請(qǐng)求回調(diào)時(shí)的方法名稱,這樣服務(wù)端在返回?cái)?shù)據(jù)時(shí)据过,將數(shù)據(jù)拼接在方法名
中惋砂,瀏覽器讀到腳本后,執(zhí)行該函數(shù)绳锅,函數(shù)里可獲得數(shù)據(jù)進(jìn)行處理.
代碼
客戶端
var script = document.createElement('script')
script.src = 'http://localhost:8000?callBack=callBack'
document.head.appendChild(script)
function callBack(data){
console.log(data.username)
console.log(data.password)
}
服務(wù)端
var http = require('http')
var url = require('url')
http.createServer(function(req,res){
var pathObj = url.parse(req.url,true)
var query = pathObj.query
var callBack = query.callBack
var data = {username:'jack',password:'123456'}
res.end(callBack + '(' + JSON.stringify(data) + ')')
}).listen(8000)
總結(jié)西饵,jsonp跨域原理是通過(guò)<script>標(biāo)簽引用接口,并且在本地定義好一個(gè)處理數(shù)據(jù)的函數(shù)鳞芙,將函數(shù)名稱傳遞后服務(wù)端眷柔,服務(wù)端接收到請(qǐng)求后,將數(shù)據(jù)放在拼裝好的函數(shù)名稱中原朝,從而達(dá)到<script>標(biāo)簽請(qǐng)求完成后驯嘱,執(zhí)行函數(shù),做到跨域數(shù)據(jù)處理喳坠。
2.CORS
客戶端
var xhr = new XMLHttpRequest();
xhr.open('GET','http://localhost:8000',true)
xhr.onload = function(){
if(xhr.status == 200){
data = JSON.parse(xhr.responseText)
console.log(data.username)
console.log(data.password)
}
}
xhr.send()
服務(wù)端
var http = require('http')
http.createServer(function (req,res) {
res.setHeader('Access-Control-Allow-Origin','*')
var data = {username:'jack',password:'123456'}
res.end(JSON.stringify(data))
}).listen(8000)
當(dāng)客戶端發(fā)送一個(gè)跨域請(qǐng)求時(shí)鞠评,瀏覽器會(huì)自動(dòng)在request header上加上
Origin:http://localhost:80801(當(dāng)前源)給服務(wù)端端
服務(wù)端如果允許跨域請(qǐng)求的話,可以通過(guò)在 response header上加上
Access-Control-Allow-Origin:源地址或者* (*代表的是所有的源都可以請(qǐng)求)
來(lái)允許某些或者所有的源獲取數(shù)據(jù)壕鹉,當(dāng)返回給客戶端后剃幌,瀏覽器會(huì)拿服務(wù)端返回的
Access-Control-Allow-Origin和客戶端的Origin進(jìn)行對(duì)比聋涨,如果匹配上了的話,客戶端可以正常使用返回的數(shù)據(jù)负乡,否則無(wú)法使用返回的數(shù)據(jù)牛郑。
3.降域
降域指的是,兩個(gè)不同源的頁(yè)面通過(guò)document.domain指定一級(jí)域名敬鬓,并且他們的一級(jí)域名相同淹朋,然后來(lái)達(dá)到相互訪問(wèn)對(duì)方頁(yè)面元素的跨域操作。(一級(jí)域名的意思請(qǐng)百度)
http://a.local.com:8000/a.html
<div>
<h1>I am a Page</h1>
</div>
<div>
<iframe src="http://b.local.com:8000/b.html"></iframe>
</div>
<script>
document.domain = 'local.com'
console.log(window.frames[0].document.head)
</script>
http://b.local.com:8000/b.html
<h1>I'm b Page</h1>
<script>
document.domain = 'local.com'
</script>
4.postMessage
采用 window.postMessage(this.value,'') 向目標(biāo)窗口(window)發(fā)送一個(gè)message類型的消息钉答,第一個(gè)參數(shù)是數(shù)據(jù)础芍,第二個(gè)參數(shù)是源名稱(代表所有源都可以接收,或者固定為固定的源数尿,例如http://localhost:8080),
目標(biāo)窗口通過(guò)addEventListener('message')的方式得到數(shù)據(jù)仑性,實(shí)現(xiàn)跨域操作。
a.html
<div>
<h1>I am a Page</h1>
<input>
</div>
<div>
<iframe src="http://b.local.com:8000/b.html"></iframe>
</div>
<script>
document.querySelector('input').addEventListener('input',function () {
window.frames[0].postMessage(this.value,'*')
})
</script>
b.html
<h1>I'm b Page</h1>
<input>
<script>
addEventListener('message',function (e) {
console.log(e.data)
document.querySelector('input').value = e.data
})
</script>