由"跨域"引出的一個終極思想(jsonp)
- 2019 年 10 月 3 日
- 筆記
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標籤).這是一種思想一種機制.