一、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,将跨域的数据请求转到本站服务器,由本站服务器去做跨域请求,即跳过浏览器同源策略的限制
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。