記錄解決跨域的筆記

爲什麼postman調接口不會跨域而瀏覽器會?
  • 都在說跨域,爲什麼postman能訪問接口,而瀏覽器就不行呢?這裏需要理解什麼是跨域,跨域是指的當前資源訪問其他資源時發起的http請求由於安全原因(由於同源策略,域名、協議。端口中只要有一個不同就不同源),瀏覽器限制了這些請求的正常訪問,特別需要注意的是這些發生在瀏覽器中。而通過postman等工具調用接口時,只是簡單的訪問一個資源,並不存在資源的相互訪問。

知識預熱
  • 回調函數

  • 這裏就不細講回調函數啦,相信各位都能理解,用一個案例來說一下。

  • “服務器”和“客戶端”初次相識,相談甚歡,客戶端希望服務器把一個叫json的東西給它,”服務器“:你先忙着,我弄好了發給你,把你電話號碼(回調函數)給我。

  • 跨域中的預檢請求即是指瀏覽器在真正發送請求前,會先發送一個Options請求嗅探,請求成功後纔會發送真實的請求。問答三連:

    • 爲什麼需要發送預檢請求?是因爲觸發了瀏覽器的安全校驗。

    • 爲什麼請求會觸發安全校驗?因爲當前請求是一個"複雜請求"。

    • 爲什麼我的請求是“複雜的”?見下面解釋

  • 複雜和簡單請求

    • 簡單請求:請求方法是GET/HEAD/POST,並且contentType爲text/plain、application/x-www-form-urlencoded、multipart/form-data。

    • 不滿足上述條件的視爲複雜請求,開發中我們常觸發這個條件大多因爲我們的請求的contentType設置的是application/json導致的。

    • 簡單請求如果設置了Authentication認證header也會讓請求“升級”爲複雜請求。

理解spring提供的@CrossOrigin註解
  
  
  
  1. @CrossOrigin(maxAge = 3600,origins = "*")

  • @CrossOrigin可以放在某個方法上,或者放在類上,這樣對類中所有請求方法有效,指定能訪問的域集合,即是設置Access-Control-Allow-Origin。

  • maxAge 屬性指定了預檢請求的緩存時間,單位是秒。對應http的Access-Control-Max-Age屬性

    • 緩存的內容爲:Access-Control-Allow-Methods和Access-Control-Allow-Headers 提供的信息。

理解使用jsonp解決跨域問題
  • 上面簡單介紹了回調函數,jsonp是如何解決跨域的呢?其實就是利用了一個特性,html頁面中引入不同域的js是不會引發跨域的,下面的案例中,我引入了一個在線的query地址,並且在script標籤的src寫上了後端的接口地址,從前端的角度我們可以想象成只是簡單請求一個js文件,js文件的內容是一個函數調用,剛好瀏覽器本地定義了這個函數,所以請求完畢,就會對這個函數發起調用,當然前後端的函數名需要一樣,這就是我們說的回調函數的機制。

  
  
  
  1. 前端

  2. <html>

  3.    <body>

  4.    <head>

  5.    <script  src="http://libs.baidu.com/jquery/1.7.2/jquery.min.js"></script>

  6.    </head>

  7.        <h3 id="test">init...</h3>

  8.    </body>

  9.    <script type="text/javascript">

  10.        //定義回調函數,相當於上述說的“電話號碼”

  11.        function myCallback(res){

  12.            alert(JSON.stringify(res));

  13.        }

  14.    </script>

  15.      <script src="http://localhost:9992/cors/infoWithCallBack"></script>

  16. --------------------------------------------------------------------------------

  17. 後端:

  18.   /**

  19.     * 返回 使用回調函數包裹的json

  20.     * @return

  21.     */

  22.    @RequestMapping("/infoWithCallBack")

  23.    public String info(){

  24.        JSONObject map = new JSONObject();

  25.        map.put("msg","請求成功!");

  26.        map.put("code","0000");

  27.        map.put("data","獲取到後端數據!");

  28.        String str = map.toString();

  29.        return "myCallback(" + str + ")";

  30.    }

  • 上面的例子在正常返回的json前面包裹了一個函數名,爲的是能讓瀏覽器執行,如果不採用jsonp的方式,而是後端設置Access-Control-Allow-Origin,則請求到的不是一個標準json,所以我們需要改造一下,兼容兩種方式。

  
  
  
  1.    <script type="text/javascript">

  2.        $(function(){


  3.            $.ajax({

  4.                type:'POST'

  5.                ,dataType:"jsonp"

  6.                ,url:'http://localhost:9992/cors/info3'

  7.                ,data:{}

  8.                ,contentType:'application/json;charset=utf-8'

  9.                //,jsonp:"callback" //指定回調函數的名字。一般不改這個,默認callback

  10.                //,jsonpCallback:"myCallback"  //手動執行發送給服務器的callback參數名,否則由jquery自動幫我們生成,類似jQuery17207352806672191685_1544278219377

  11.                ,success:function(data){

  12.                debugger;          

  13.                    alert("ajax: "+JSON.stringify(data));

  14.                }

  15.            });


  16.        }

  17.    </script>

  18. --------------------------------------------------------------------------------

  19. /**

  20.     * 3.兼容jsonp和普通json請求

  21.     * @return

  22.     */

  23.    @RequestMapping("/info3")

  24.    public String info3(@RequestParam(name="callback",required = false) String callBack){

  25.        JSONObject map = new JSONObject();

  26.        map.put("msg","請求成功!");

  27.        map.put("code","0000");

  28.        map.put("data","獲取到後端數據!");

  29.        String result = map.toString();

  30.        if(!StringUtils.isEmpty(callBack)){

  31.            //如果是json請求,則包裹上回調函數

  32.            return callBack + "(" + result + ")";

  33.        }

  34.        return result;

  35.    }

其他遇到的問題
  
  
  
  1. Uncaught SyntaxError: Unexpected token :

  • 在解決跨域時,遇到這種錯誤,一般是前端沒有設置回調函數,而後端返回了被回調函數包裹的json.

  
  
  
  1. info?callback=callback:1 Uncaught ReferenceError: callback is not defined

  2.    at info?callback=callback:1

  • 回調函數未定義,請求後端接口的script標籤必須在聲明的回調函數之後定義,否則會報錯。

  • 代碼已push到俠夢的github,https://github.com/Hyq0823/Stardust/tree/master/src/main/java/com/cors


本文分享自微信公衆號 - 俠夢的開發筆記(xmdevnote)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章