您的位置:首页 > Web前端 > JavaScript

Json和JsonP及ajax跨域的解决办法

2017-03-31 18:35 441 查看
JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。我们拿最近比较火的谍战片来打个比方,JSON是地下党们用来书写和交换情报的“暗号”,而JSONP则是把用暗号书写的情报传递给自己同志时使用的接头方式。看到没?一个是描述信息的格式,一个是信息传递双方约定的方法。

JSON的优点:

  1、基于纯文本,跨平台传递极其简单;

  2、Javascript原生支持,后台语言几乎全部支持;

  3、轻量级数据格式,占用字符数量极少,特别适合互联网传递;

  4、可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;

  5、容易编写和解析,当然前提是你要知道数据结构;

原理:

ajax本身是不可以跨域的,通过产生一个script标签来实现跨域。因为script标签的src属性是没有跨域的限制的。其实设置了dataType: ‘jsonp’后,$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议。JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问。

ajax跨域到底是什么意思?

Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest 函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。不过,由于受到浏览器的限制,该方法不允许跨域通信。如果尝试从不同的域请求数据,会出现安全错误。如果能控制数 据驻留的远程服务器并且每个请求都前往同一域,就可以避免这些安全错误。

Ajax请求一个目标地址为非本域(协议、域名、端口任意一个不同)的web资源,并根据响应获得外部应用数据。比如我们用Ajax访问城市天气预报、IP地址等公共服务接口时,就涉及跨域了。我们请求一个外部服务时,浏览器会基于安全问题拒绝授权访问。而script、script、iframe标签的src属性就不存在跨域的问题

1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;

  2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如script、img、iframe);

  3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;

  4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;

  5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。

  6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。

  7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

缺点:使用jsonp,jQuery的ajax方法支持jsonp,但是最大的缺点就是只支持get方式,而且服务端也要修改

我的实例:

$(".btnMallShop").click(function() {
$.ajax({
url : cartUrlBase + '/api/cartApi/addCartApi',
type : 'get',
data : {
logBatch : $("#logBatch").val(),
token : $("#token").val(),
wareId : $(this).parents('tr').find(".ware-id").val(),
price : $(this).closest('tr').find('.price-store').text(),
traderId : $("#firmId").val(),
wareStatus : 'B'
},
dataType : 'jsonp',
jsonpCallback : "addCart",
success : function(date) {
util.dialog({
title : date.msg,
content : "购物车数量为" + date.count + ",您可以",
okValue : '购物车结算',
ok : function() {
window.location.href = cartUrlBase + "/cart/cartView"
},
cancelValue : '继续购物',
cancel : function() {
}
});
},
error : function(e) {
alert("cuowu");
}
});


后端:

@ApiOperation(value = "购物车", notes = "添加购物车", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_VALUE)
@RequestMapping(value = "/addCartApi", method = RequestMethod.GET )
@ResponseBody
public JSONPObject addCartApi(  HttpServletRequest request,
HttpServletResponse response,
@ApiParam(value = "日志批次号") @RequestParam(required = true) String logBatch,
@ApiParam(value = "授权token") @RequestParam(required = true) String token,
@ApiParam(value = "商品id") @RequestParam(required = true) String wareId,
@ApiParam(value = "价格快照") @RequestParam(required = true) String price,
@ApiParam(value = "交易摊位号") @RequestParam(required = true) String traderId,
@ApiParam(value = "商品状态") @RequestParam(required = true) String wareStatus) {
//ApiResult apiResult = null;
Map<String,Object> map = new HashMap<String,Object>();
try {
if (!super.authApi(token)) {// 没有登录
List<String> wareIdList = new ArrayList<String>();
super.logInfo(traderId, logBatch, "未登录添加购物车", "开始执行", EnumMonitorLog.LOGSYSTEM_CART.getKey());
String cartInfo = CookieUtils.getCookieValue(request, CookieConstant.CART_INFO);
if(cartInfo!=null){
wareIdList = new ArrayList<>(Arrays.asList(cartInfo.split(",")));
//验证商品是否已经在购物车
for(String s:wareIdList){
if(s.equals(wareId)){
map.put("msg", "购物车已有此商品");
map.put("count", wareIdList.size());
return new JSONPObject("addCart", map);
}
}

}
wareIdList.add(wareId);
String[] s = new String[wareIdList.size()];
wareIdList.toArray(s);
String wareIds = StringUtils.join(s, ",");
// 加入cookie
CookieUtils.setCookie(request, response, CookieConstant.CART_INFO, wareIds, 0);
super.logInfo(traderId, logBatch, "未登录添加购物车添加完成", "执行结果,添加购物车成功", EnumMonitorLog.LOGSYSTEM_CART.getKey());
map.put("msg", "添加购物车成功");

/*
super.logInfo(traderId, logBatch, "未登录查询购物车商品数量", "开始执行", EnumMonitorLog.LOGSYSTEM_CART.getKey());
cartInfo = CookieUtils.getCookieValue(request, CookieConstant.CART_INFO);
if(cartInfo!=null){
wareIdList = Arrays.asList(cartInfo.split(","));
map.put("count", wareIdList.size());
}else{
map.put("count", 0);
}
super.logInfo(traderId, logBatch, "未登录查询购物车商品数量", "执行结果购物车数量" + wareIdList.size(), EnumMonitorLog.LOGSYSTEM_CART.getKey());
*/
map.put("count", wareIdList.size());
} else {
super.logInfo(traderId, logBatch, "登录状态添加购物车", "开始执行", EnumMonitorLog.LOGSYSTEM_CART.getKey());
// 判断是否在购物车
boolean isInCart = cartService.isInCart(wareId, traderId);
if (isInCart) {
map.put("msg", "购物车已有此商品");
super.logInfo(traderId, logBatch, "登录状态添加购物车完成", "执行结果,购物车已有此商品", EnumMonitorLog.LOGSYSTEM_CART.getKey());
} else {
cartService.addCart(wareId, traderId, price, wareStatus);
//apiResult = new ApiResult(ApiResult.STATE_CODE_SUCCESS, null, "添加购物车成功");
map.put("msg", "添加购物车成功");
super.logInfo(traderId, logBatch, "登录状态添加购物车完成", "执行结果,添加购物车成功", EnumMonitorLog.LOGSYSTEM_CART.getKey());
}

super.logInfo(traderId, logBatch, "登录状态查询购物车商品数量", "开始执行", EnumMonitorLog.LOGSYSTEM_CART.getKey());
int count = cartService.getCartRollCount(traderId, null);
map.put("count", count);
super.logInfo(traderId, logBatch, "登录状态查询购物车商品数量", "执行结果购物车数量" + count, EnumMonitorLog.LOGSYSTEM_CART.getKey());

}

}
catch (CartApiException e) {
map.put("msg", "添加购物车失败");
super.logError( traderId,
logBatch,
"添加购物车出现错误",
e.getMessage(),
Boolean.getBoolean(redisSpringService.get(EnumMonitorLog.LOG_NOTIFY_SWITCH.getKey())),
EnumMonitorLog.LOGSYSTEM_CART.getKey());
}
JSONPObject obj = new JSONPObject("addCart", map);
return obj;
}


详情参考:http://kb.cnblogs.com/page/139725/

同源策略:https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

ajax跨域的另外两种解决方式:

1.代理

2.XHR2

HTML5中提供的XMLHTTPREQUEST Level2(及XHR2)已经实现了跨域访问。但ie10以下不支持

只需要在服务端填上响应头:

header(“Access-Control-Allow-Origin:*”);

/星号表示所有的域都可以接受,/

header(“Access-Control-Allow-Methods:GET,POST”);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: