1.背景介紹
所有支持Javascript的瀏覽器都會(huì)使用同源策略這個(gè)安全策略升薯。導(dǎo)致我們無法直接訪問非同源的鏈接匿级,無法取得非同源的數(shù)據(jù)顿乒,但在項(xiàng)目中我們的數(shù)據(jù)經(jīng)常寫在另一個(gè)源中削樊,于是我們需要突破同源限制青团,取得其他源的數(shù)據(jù)何什,這就叫跨域组哩。
2.知識(shí)剖析
常見的跨域方法有:
- jsonp,利用了src屬性可以跨域的特性
- document.domain跨子域
- Access Control,服務(wù)器端發(fā)送Access-Control-Allow-Origin響應(yīng)頭,規(guī)定請(qǐng)求的域名的訪問權(quán)限
- nginx反向代理处渣,客戶端nginx攔截代碼中虛假的http請(qǐng)求伶贰,替換成正確的http
如何算不同的域?
- 不同域名
- 同一域名罐栈,不同端口
- 同一域名黍衙,不同協(xié)議
- 域名和域名對(duì)應(yīng)ip
- 主域相同,子域不同
- 同一域名荠诬,不同二級(jí)域名
3.常見問題
jsonp是如何實(shí)現(xiàn)跨域的
4.解決方案
有兩個(gè)文件處于不同域中:
A.html
<script type="text/javascript">
//回調(diào)函數(shù)
function callback(data) {
alert(data.message);
}
</script>
<script type = "text/javascript" src ="http://localhost:20002/B.js"></script>
B.js
//調(diào)用callback函數(shù)琅翻,并以json數(shù)據(jù)形式作為闡述傳遞,完成回調(diào)
callback({message: "success"});
結(jié)果會(huì)alert“success”柑贞,這就是jsop的基本原理
5.編碼實(shí)戰(zhàn)
客戶端:
<script>
//顯示后臺(tái)返回?cái)?shù)據(jù)的一個(gè)屬性
function jsonp(data) {
//alert傳入的data數(shù)組項(xiàng)中的一個(gè)屬性
alert(JSON.parse(data)[0].location);
}
//添加<script>標(biāo)簽的方法
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type", "text/javascript");
script.src = src;
document.body.appendChild(script);
}
//防止script標(biāo)簽放在頭部運(yùn)行時(shí)方椎,body還未渲染
window.onload = function () {
//將數(shù)據(jù)從url中提取出來,便于添加數(shù)據(jù)钧嘶。
var name = "馮強(qiáng)", age = 24, callback = "jsonp";
addScriptTag("http://59.110.174.154/test/test1.js?name=" + name + "&age=" + age + "&callback=" + callback);
}
</script>
服務(wù)器端:
//定義一些變量
var name,age,callback,data=[];
//遍歷script標(biāo)簽
[].forEach.call(document.scripts, function (val, index, arr) {
if (val.src) {
//使用正則表達(dá)式匹配url字符串棠众,并在回調(diào)函數(shù)中將我們需要的參數(shù)傳遞給變量
decodeURI(val.src).replace(/.*\?name=(.*)&age=(.*)&callback=(.*)/g, function (match, p1, p2,p3,offset,string) {
name=p1;
age=p2;
callback=p3;
});
}
});
//數(shù)據(jù)庫的一段JSON代碼
var json=[
{"name":"小宇","age":"24","location":"襄陽"},
{"name":"恒光","age":"24","location":"益陽"},
{"name":"馮強(qiáng)","age":"24","location":"黃岡"}
]
//遍歷json,查詢符合參數(shù)的項(xiàng),屏添加到data數(shù)組中
json.forEach(function(val,index,arr){
if(val.name===name&&val.age===age){
data.push(json[index]);
}
})
//JSON化data數(shù)組
data=JSON.stringify(data);
//使用eval解析callback函數(shù)名闸拿,并傳入data參數(shù)空盼,執(zhí)行函數(shù)
eval(callback)(data);
6.擴(kuò)展思考
jsonp跨域有什么優(yōu)缺點(diǎn)?
優(yōu)點(diǎn):兼容性很好好新荤,可以在古老的瀏覽器中運(yùn)行揽趾,
缺點(diǎn):它只支持GET請(qǐng)求而不支持POST等其它類型的HTTP請(qǐng)求。
jsonp和ajax有什么關(guān)系迟隅?
ajax是通過操作XMLHttpRequest對(duì)象發(fā)送請(qǐng)求但骨,獲取返回的數(shù)據(jù)。JSONP的全稱為JSON
with Padding智袭,Padding指的就是包裹在JSON外層的回調(diào)函數(shù)奔缠。從剛才的例子中,咱們發(fā)現(xiàn)JSONP并沒有操作XMLHttpRequest吼野,因此jsonp和ajax沒有任何關(guān)系校哎。
如何用jQuery實(shí)現(xiàn)JSONP
前端代碼:
$.ajax({
url: "http://tonghuashuo.github.io/test/jsonp.txt",
dataType: 'jsonp',
jsonp: "callback",
jsonpCallback: "dosomething"
})
.done(function (res) {
console.log("success");
console.log(res);
})
.fail(function (res) {
console.log("error");
console.log(res);
});
這里使用了ajax這個(gè)方法,但實(shí)際上jsonp和ajax沒有任何關(guān)系瞳步,只是因?yàn)閖sonp請(qǐng)求和ajax請(qǐng)求相似闷哆,jquery在這里有誤導(dǎo)之嫌。
7.參考文獻(xiàn)
參考一:跨域資源共享CORS詳解
參考二:5分鐘徹底明白JSONP
參考三:深入淺出JSONP--解決ajax跨域問題