1. 程式人生 > >由"跨域"引出的一個終極思想(jsonp)

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

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標籤).這是一種思想一種機制.