由"跨域"引出的一個終極思想(jsonp)
1.什麼是跨域?
當協議、子域名、主域名、埠號中任意一個不相同時,都算作不同域. 跨域並不是請求發不出去,請求能發出去,服務端能收到請求並正常返回結果,但是因為瀏覽器存在一個"同源策略",結果就被瀏覽器攔截了。
舉個例子:當一個頁面中存在js或者jq的ajax請求,當該請求與當前域中的協議、子域名、主域名、埠號中任意一個不相同時,都是跨域,
最後再簡單來說:瀏覽器具有“同源策略”,即:因為瀏覽器存在一個"同源策略",瀏覽器只能想當前所在的域傳送Ajax,如果向其他域傳送請求,則瀏覽器就會報錯。
2.處理跨域的兩種方法
解決辦法有兩個:
cors方法:
這個方法是一個主流方法,通過設定響應物件的響應頭,去強制允許瀏覽器接受跨域的響應物件
def api (request) : ret : = HttpResponse('百度') ret["Access-Control- Allow -Origin"] = "*” #設定響應物件的響應頭,接受任何跨域響應物件 return ret
jsonp:這是一種思想,不是處理跨域問題的最好方法,絕對的爆炸思想
- 一個解決跨域的方案,是一種巧妙的機制,可以繞過瀏覽器的同源策略,實現跨域(動態建立script標籤)。
- 精華在第三部分!
3.終極思想(精華部分)
再次宣告: jsonp這是一種思想,不是解決跨域的最好辦法,只是一個解決跨域的方案,是一種巧妙的機制,可以繞過瀏覽器的同源策略,實現跨域(動態建立script標籤)。但是這個思想是真的牛逼,一起來看
- 首先想一下跨域的根本原因:因為瀏覽器存在一個"同源策略",瀏覽器只能想當前所在的域傳送Ajax,如果向其他域傳送請求,則瀏覽器就會報錯。
- 瀏覽器存在同源策略
- 阻止請求的響應物件
3.1 js跨域示例:
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script> // 同源請求 function sendMsg1() { $.ajax({ url:'/msg/',//預設埠8000 type:'GET', success:function (arg) { console.log(arg); } }) } // 跨域請求 function sendMsg2() { $.ajax({ url:'http://127.0.0.1:9000/api/', type:'GET', success:function (arg) { console.log(arg); } }) } </script>
跨域請求觸發時報錯:
重點來了,到了這不知道你有沒有留意一點,ajax的請求的響應物件雖然被攔截了,但是所引用的jquery源<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
依然生效! 天吶,ajax是跨域,jquery就不是?也是!因為當協議、子域名、主域名、埠號中任意一個不相同時,都算作不同域!但是為什麼沒有攔截我的jquery呢?
- 因為
src
擁有"同源策略"的通行證!,也就是同源策略不會攔截src屬性的請求響應物件
既然是這樣,那如果我在<script>
標籤的src中寫入一個我的請求url呢? 搞事情!
3.2 jsonp繞過同源策略示例
- 因為
src
擁有"同源策略"的通行證!,也就是同源策略不會攔截src屬性的請求響應物件
// 前端頁面
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
// 同源請求
function sendMsg1() {
$.ajax({
url:'/msg/',
type:'GET',
success:function (arg) {
console.log(arg);
}
})
}
// 依舊跨域
function sendMsg2() {
var tag = document.createElement('script'); //建立一個script標籤
tag.src = 'http://127.0.0.1:9000/api/?callback=f1'; //更改src屬性
document.head.appendChild(tag); // 新增到head中
document.head.removeChild(tag); //刪除該標籤
}
function f1(arg) { // 請求響應完畢後,要執行的函式
console.log(arg);
}
</script>
# 目標域的api介面
def api(request):
func_name = request.GET.get('callback')
return HttpResponse('%s("百度")' %func_name) # 靈活接受前端的引數,並將該引數和資料一起返回
呼~建立一個script標籤, 更改src屬性,新增到head中,刪除該標籤,一氣呵成,完美跨域!
- 建立一個
script
標籤,更改src:
在跨域請求出發時,建立一個script標籤,並將src的值賦值為要請求的url,並動態設定引數callback=f1,f1是為了返回物件後執行定義的f1函式,出發自定義的動作
將自定義的script標籤新增到head中
將自定義的script標籤新增到head中後,script標籤就會根據url請求一個js檔案,並按照javascript的方式執行,也就是去url請求一個響應物件,也就是 f1("百度"),你是不是想到了什麼?沒錯,如果在此時你定義了 function f1(arg) { console.log(arg); } 這麼一個函式,這個函式就會被執行,那麼跨域的問題不就解決了,也就是可以任你擺佈了
刪除該標籤
在head添加了script標籤,得到f1("百度")後f1函式會立即執行,防止多次請求head中script標籤過多,刪了就行!
大功告成!
- 不過呢jsonp只能發get請求,
小結
瀏覽器的"同源策略"不會攔截src的請求響應,通過該機制就可以繞過瀏覽器的同源策略.
再重複一次:jsonp一個解決跨域的方案,是一種巧妙的機制,可以繞過瀏覽器的同源策略,實現跨域(動態建立script標籤).這是一種思想一種機制.