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或拒绝解析的问题。
根据第三步问题缘由的分析中可知,修改方法有以下两种: