一、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>
呼叫結果
如上,當在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>
呼叫結果
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>
呼叫結果
通過指定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解決跨域的請求出現如下錯誤:
如上,如果服務端程式碼沒有指定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時,會拒絕以下兩種請求:
- 請求型別: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或拒絕解析的問題。
四、解決辦法
根據第三步問題原因的分析中可知,修改方法有如下兩種:
- 去除服務端response.addHeader("X-Content-Type-Options", "nosniff");的配置,但可能造成一些安全上的問題,筆者這裡不做擴充套件,有興趣的同學可以留言討論
- 服務指定Content-Type為Javascript型別的一種即可
- 啟用jsonp,將跨域的資料請求轉到本站伺服器,由本站伺服器去做跨域請求,即跳過瀏覽器同源策略的限制