由"跨域"引出的一個終極思想(jsonp)

  • 2019 年 10 月 3 日
  • 筆記

1.什麼是跨域?

  • 當協議、子域名、主域名、埠號中任意一個不相同時,都算作不同域. 跨域並不是請求發不出去,請求能發出去,服務端能收到請求並正常返回結果,但是因為瀏覽器存在一個"同源策略",結果就被瀏覽器攔截了。

    • 舉個例子:當一個頁面中存在js或者jq的ajax請求,當該請求與當前域中的協議、子域名、主域名、埠號中任意一個不相同時,都是跨域,

    • 最後再簡單來說:瀏覽器具有「同源策略」,即:因為瀏覽器存在一個"同源策略",瀏覽器只能想當前所在的域發送Ajax,如果向其他域發送請求,則瀏覽器就會報錯。

2.處理跨域的兩種方法

解決辦法有兩個:

  1. cors方法:

    • 這個方法是一個主流方法,通過設置響應對象的響應頭,去強制允許瀏覽器接受跨域的響應對象

      def api (request) :     ret : = HttpResponse('百度')     ret["Access-Control- Allow -Origin"] = "*」  #設置響應對象的響應頭,接受任何跨域響應對象     return ret
  2. 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標籤).這是一種思想一種機制.

Tags: