jsonp是實現跨域請求數據的一種方式,解決了因爲瀏覽器同源策略帶來的安全限制;雖然瀏覽器有同源策略的限制,但對於一些特殊的dom元素卻可引用非同源資源,例如<img src=""/> <script src=""/>等,下面結合例子說明:javascript
服務端代碼css
@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); }
客戶端代碼html
<!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>
調用結果
如上,當在localhost:9090站點訪問localhost:8080的接口資源時,出現跨域錯誤。java
如錯誤提示,可在服務器端代碼中設置響應頭「Access-Control-Allow-Origin」實現容許跨域
服務端代碼
如上不變jquery
客戶端代碼ajax
<!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>
調用結果json
服務端代碼
如上不變跨域
客戶端代碼瀏覽器
<!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>
調用結果安全
經過指定ajax的dataType爲「jsonp」,jsonp指定服務端返回jsonp格式數據;請求會自動帶上參數callback=?
當服務端代碼中添加安全響應頭時:
服務端代碼
@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解決跨域的請求出現以下錯誤:
如上,若是服務端代碼沒有指定ContentType時,則出現以下錯誤:
以上均是由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時,會拒絕如下兩種請求:
因此,當服務端出現response.addHeader("X-Content-Type-Options", "nosniff");安全相應頭,且未指定Content-Type爲Javascript類型類型時,jsonp請求跨域資源時變出現如上CORB或拒絕解析的問題。
根據第三步問題緣由的分析中可知,修改方法有以下兩種: