jsonp跨域資源引起CORB

一、jsonp的使用

jsonp是實現跨域請求數據的一種方式,解決了由於瀏覽器同源策略帶來的安全限制;雖然瀏覽器有同源策略的限制,但對於一些特殊的dom元素卻可引用非同源資源,例如<img src=""/> <script src=""/>等,下面結合例子說明:

  • jquery直接發起ajax調用

服務端代碼

@RequestMapping(value = "/load/data")
public void loadData2(@RequestParam("callback") String callback,
                     HttpServletResponse response) throws IOException {
    Map<String, String> data = new HashMap<>();
    data.put("name", "xudj");
    data.put("age", "18");
    // 轉json
    String jsonData = JSON.toJSONString(data);

    //用回調函數名稱包裹返回數據
    String result = callback + "(" + jsonData + ")";
    response.getWriter().write(result);
}

客戶端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跨域測試</title>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
    <script>
        $(document).ready(function () {
            $("#btn").click(function () {
                $.ajax({
                    url: 'http://localhost:8080/load/data',
                    type: 'GET',
                    success: function (data) {
                        $(text).val(data);
                    }
                });
            });
        });
    </script>
</head>
<body>
<input id="btn" type="button" value="跨域請求數據" />
<textarea id="text" style="width: 200px; height: 100px;"></textarea>
</body>
</html>

調用結果
cors跨域
如上,當在localhost:9090站點訪問localhost:8080的接口資源時,出現跨域錯誤。

如錯誤提示,可在服務器端代碼中設置響應頭“Access-Control-Allow-Origin”實現允許跨域
  • script解決跨域問題

服務端代碼
如上不變

客戶端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>script解決跨域</title>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
    <script>
        //回調函數
        function showData (result) {
            //json對象轉成字符串
            var data = JSON.stringify(result);
            $("#text").val(data);
        }
        $(document).ready(function () {
            $("#btn").click(function () {
                // 向頭部輸入一個腳本,該腳本發起一個跨域請求
                $("head").append("<script src='http://localhost:8080/load/data?callback=showData'><\/script>");
            });
        });
    </script>
</head>
<body>
<input id="btn" type="button" value="跨域請求數據" />
<textarea id="text" style="width: 200px; height: 100px;"></textarea>
</body>
</html>

調用結果
script解決cprs

  • jsonp解決跨域

服務端代碼
如上不變

客戶端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp解決跨域</title>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
    <script>
        // 回掉函數,默認callback=jQuery30004159376653216822_1550582355513
        function showData(data) {
            console.info("Get Into showData");
            // json對象轉成字符串
            var result = JSON.stringify(data);
            $("#text").val(result);
        }
        // 調用
        $(document).ready(function () {
            $("#btn").click(function () {
                $.ajax({
                    url: "http://localhost:8080/load/data",
                    type: "GET",
                    dataType: "jsonp", //指定服務器返回的數據類型
                    jsonpCallback: "showData",  // 指定回調函數名稱或直接使用回掉函數success
                    jsonp: "callback",   // 默認callback
                    success: function (data) {
                        console.info("Get Into success");
                        // json對象轉成字符串
                        // var result = JSON.stringify(data);
                        // $("#text").val(result);
                    }
                });
            });
        });
    </script>
</head>
<body>
<input id="btn" type="button" value="跨域請求數據"/>
<textarea id="text" style="width: 200px; height: 100px;"></textarea>
</body>
</html>

調用結果
jsonp解決跨域

通過指定ajax的dataType爲“jsonp”,jsonp指定服務端返回jsonp格式數據;請求會自動帶上參數callback=?

二、CORB問題的由來

當服務端代碼中添加安全響應頭時:
服務端代碼

@RequestMapping(value = "/load/data")
    public void loadData2(@RequestParam("callback") String callback,
                         HttpServletResponse response) throws IOException {
        // 安全響應頭
        response.addHeader("X-Content-Type-Options", "nosniff");
        response.setContentType("text/html;charset=UTF-8");

        Map<String, String> data = new HashMap<>();
        data.put("name", "xudj");
        data.put("age", "18");
        // 轉json
        String jsonData = JSON.toJSONString(data);

        //用回調函數名稱包裹返回數據
        String result = callback + "(" + jsonData + ")";
        response.getWriter().write(result);
    }
如上所示,代碼中多出
// 安全響應頭
response.addHeader("X-Content-Type-Options", "nosniff");
response.setContentType("text/html;charset=UTF-8");

導致使用jsonp解決跨域的請求出現如下錯誤:
jsonp出現CORB

如上,如果服務端代碼沒有指定ContentType時,則出現如下錯誤:

jsonp拒絕執行script
以上均是由response.addHeader("X-Content-Type-Options", "nosniff");導致的瀏覽器執行script時通過對MIME類型檢測過濾掉不安全的文件或請求。

三、原因分析

CORB(Cross-Origin Read Blocking):瀏覽器在加載可以跨域資源時,在將資源載入頁面時對其進行識別與攔截等一系列處理。
X-Content-Type-Options(:nosniff):相當於一個提示標誌,被服務器用來提示客戶端須遵循在Content-Type首部中對MIME類型的設定,不能對其進行修改。從而禁用了客戶端(瀏覽器)的MIME類型嗅探行爲(即把不可執行的MIME類型轉變爲可執行的MIME類型)。指定值爲nosniff時,會拒絕以下兩種請求:
  • 請求類型:style,MIME類型不是“text/css”
  • 請求類型:script,MIME類型不是“Javascript類型”,Javascript類型有text/javascript、application/javascript、application/x-javascript等

所以,當服務端出現response.addHeader("X-Content-Type-Options", "nosniff");安全相應頭,且未指定Content-Type爲Javascript類型類型時,jsonp請求跨域資源時變出現如上CORB或拒絕解析的問題。

四、解決辦法

根據第三步問題原因的分析中可知,修改方法有如下兩種:

  1. 去除服務端response.addHeader("X-Content-Type-Options", "nosniff");的配置,但可能造成一些安全上的問題,筆者這裏不做擴展,有興趣的同學可以留言討論
  2. 服務指定Content-Type爲Javascript類型的一種即可
  3. 啓用jsonp,將跨域的數據請求轉到本站服務器,由本站服務器去做跨域請求,即跳過瀏覽器同源策略的限制
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章