一、 跨域访问
在某个A网站中,我们希望使用Ajax来获得某个B网站中的特定内容。如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。
二、JSONP
JSONP(JSON With Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
一般来说位于 serverA.example.com 的网页无法与不是 serverB.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用<script>元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
三、JSONP的使用实例
1、前端Ajax发送请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsonp test</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.min.js"></script>
<script type="text/javascript">
function apitest(){
$.ajax({
url :'http://localhost:1000/test',//访问的链接
type : "GET", // 请求方式
dataType:"jsonp",// 从后端返回的数据类型
crossDomain:true,//是否跨域
jsonpCallback:"callback",//为JSONP请求指定的callback函数的名称
jsonp:"callback",//跨域函数名的键值,即服务端提取函数名的key(默认为callback)
success: function(data) { 请求成功的回调函数,data为要获得的数据
var html = "<p>"+JSON.stringify(data)+"</p>";//object to detail
$("#data-detail").html(html);
// console.log(data);
// alert(JSON.stringify(data));
},
error: function(data) {//请求失败的回调函数
alert( "error" );
}
});
}
</script>
</head>
<body>
<h1>Get data with ajax</h1>
<input type="button" value="get data" onclick="apitest()">
<div id="data-detail"></div>
</body>
</html>
2、后端响应请求
#设置response的contentType
@RequestMapping(value = {"/test"},method = RequestMethod.GET,produces = "text/javascript;charset=UTF-8")
public String getJsonp(@RequestParam("callback") String callback,
HttpServletResponse response) {
#设置response的header
response.setHeader("Access-Control-Allow-Origin","*");
Map<String,String> data=new HashMap<>();
data.put("test","1");
//构造返回值
callback + "(" + JSONArray.toJSONString(data,SerializerFeature.WriteMapNullValue) + ")";
}
(1)response的contentType类型
ajax开发中在请求服务器端的响应时, 对于每一种返回类型,需要在服务端指定response的contentType ,常遇到下面的几种情况:
a. 服务端需要返回一段普通文本给客户端,Content-Type=”text/plain”
b. 服务端需要返回一段HTML代码给客户端 ,Content-Type=”text/html”
c. 服务端需要返回一段XML代码给客户端 ,Content-Type=”text/xml”
e. 服务端需要返回一段javascript代码给客户端,Content-Type=”text/javascript”
f. 服务端需要返回一段json串给客户端,,Content-Type=”text/json”
需要注意:spring mvc不能使用response.setHeader("Content-Type", "text/javascript; charset=UTF-8");设置contentType,设置了虽然不会报错,但不会生效。
原因:参考这篇文章:https://www.cnblogs.com/kaiblog/p/7565231.html
设置方法:
@Controller
@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
// implementation omitted
}
(2)response header其他信息
response.setHeader("Access-Control-Allow-Origin","*");// 指定允许其他域名访问
response.setHeader("Access-Control-Allow-Methods","GET,POST");// 响应类型
(3)to json
当value为null时,JSONObject.toJSONString()返回的json字符串将不展示对应的key。
可以使用JSONObject.toJSONString(Object object, SerializerFeature... features) ,其中SerializerFeature属性对应的值和含义如下:
a. QuoteFieldNames 输出key时是否使用双引号,默认为true
b. UseSingleQuotes 使用单引号而不是双引号,默认为false
c. WriteMapNullValue 是否输出值为null的字段,默认为false
e. WriteEnumUsingToString Enum输出name()或者original,默认为false
f. UseISO8601DateFormat Date使用ISO8601格式输出,默认为false
j. WriteNullListAsEmpty List字段如果为null,输出为[],而非null
h. WriteNullStringAsEmpty 字符类型字段如果为null,输出为”“,而非null
i. WriteNullNumberAsZero 数值字段如果为null,输出为0,而非null
j. WriteNullBooleanAsFalse Boolean字段如果为null,输出为false,而非null
k. SkipTransientField 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
l. SortField 按字段名称排序后输出。默认为false
m. WriteTabAsSpecial 把\t做转义输出,默认为false
n. PrettyFormat 结果是否格式化,默认为false
o. WriteClassName 序列化时写入类型信息,默认为false。反序列化是需用到
p. DisableCircularReferenceDetect 消除对同一对象循环引用的问题,默认为false
q. WriteSlashAsSpecial 对斜杠’/’进行转义
r. BrowserCompatible 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
s. WriteDateUseDateFormat 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
参考文章:
https://api.jquery.com/jQuery.ajax/
https://www.cnblogs.com/kaiblog/p/7565231.html