重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的跨域问题。本篇将讲述一个小白从遇到跨域不知道是跨域问题,到知道是跨域问题不知道如何解决,再到解决跨域问题,最后找到两种方法解决ajax 跨域问题的全过程。
站在用户的角度思考问题,与客户深入沟通,找到眉山网站设计与眉山网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:网站设计、网站制作、企业官网、英文网站、手机端网站、网站推广、主机域名、网页空间、企业邮箱。业务覆盖眉山地区。
不知是跨域问题
起 因是这样的,为了复用,减少重复开发,单独开发了一个用户权限管理系统,共其他系统获取认证与授权信息,暂且称之为A系统;调用A系统以B为例。在B系统 中用ajax调用A系统系统的接口(数据格式为json),当时特别困惑,在A系统中访问相应的url可正常回返json数据,但是在B系统中使用 ajax请求同样的url则一点儿反应都没有,好像什么都没有发生一样。这样反反复复改来改去好久都没能解决,于是求救同事,提醒可能是ajax跨域问 题,于是就将这个问题当做跨域问题来解决了。
知跨域而不知如何解决
知道问题的确切原因,剩下的就是找到解决问题的方法了。google了好久,再次在同事的指点下知道jQuery的ajax有jsonp这样的属性可以用来解决跨域的问题。
找到一种解决方式
现在也知道了怎样来解决跨域问题,余下的就是实现的细节了。实现的过程中错误还是避免不了的。由于不了解json和jsonp两种格式的区别,也犯了错误,google了好久才解决。
首先来看看在页面中如何使用jQuery的ajax解决跨域问题的简单版:
复制代码
$(document).ready(function(){
var url='"
+"?id=1callback=?';
$.ajax({
url:url,
dataType:'jsonp',
processData: false,
type:'get',
success:function(data){
alert(data.name);
},
error:function(XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.readyState);
alert(textStatus);
}});
});
复制代码
这样写是完全没有问题的,起先error的处理函数中仅仅是alert(“error”),为了进一步弄清楚是什么原因造成了错误,故将处理函数变 为上面的实现方式。最后一行alert使用为;parsererror。百思不得其解,继续google,最终还是在万能的stackoverflow找 到了答案,链接在这里。原因是jsonp的格式与json格式有着细微的差别,所以在server端的代码上稍稍有所不同。
比较一下json与jsonp格式的区别:
json格式:
{
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
}
jsonp格式:
callback({
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
})
看出来区别了吧,在url中callback传到后台的参数是神马callback就是神马,jsonp比json外面有多了一层,callback()。这样就知道怎么处理它了。于是修改后台代码。
后台java代码最终如下:
复制代码
@RequestMapping(value = "/getGroupById")
public String getGroupById(@RequestParam("id") Long id,
HttpServletRequest request, HttpServletResponse response)
throws IOException {
String callback = request.getParameter("callback");
ReturnObject result = null;
Group group = null;
try {
group = groupService.getGroupById(id);
result = new ReturnObject(group, "获取成功", Constants.RESULT_SUCCESS);
} catch (BusinessException e) {
e.printStackTrace();
result = new ReturnObject(group, "获取失败", Constants.RESULT_FAILED);
}
String json = JsonConverter.bean2Json(result);
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.print(callback + "(" + json + ")");
return null;
}
复制代码
注意这里需要先将查询结果转换我json格式,然后用参数callback在json外面再套一层,就变成了jsonp。指定数据类型为jsonp的ajax就可以做进一步处理了。
虽然这样解决了跨域问题,还是回顾下造成parsererror的原因。原因在于盲目的把json格式的数据当做jsonp格式的数据让ajax处理,造成了这个错误,此时server端代码是这样的:
复制代码
@RequestMapping(value = "/getGroupById")
@ResponseBody
public ReturnObject getGroupById(@RequestParam("id") Long id,
HttpServletRequest request, HttpServletResponse response){
String callback = request.getParameter("callback");
ReturnObject result = null;
Group group = null;
try {
group = groupService.getGroupById(id);
result = new ReturnObject(group, "获取成功", Constants.RESULT_SUCCESS);
} catch (BusinessException e) {
e.printStackTrace();
result = new ReturnObject(group, "获取失败", Constants.RESULT_FAILED);
}
return result;
}
复制代码
至此解决ajax跨域问题的第一种方式就告一段落。
追加一种解决方式
追求永无止境,在google的过程中,无意中发现了一个专门用来解决跨域问题的jQuery插件-jquery-jsonp。
有第一种方式的基础,使用jsonp插件也就比较简单了,server端代码无需任何改动。
来看一下如何使用jquery-jsonp插件解决跨域问题吧。
复制代码
var url=""
+"?id=1callback=?";
$.jsonp({
"url": url,
"success": function(data) {
$("#current-group").text("当前工作组:"+data.result.name);
},
"error": function(d,msg) {
alert("Could not find user "+msg);
}
});
跨域问题一般都在后台程序解决,将自己的程序通过配置文件或者代码将其允许跨域,
在有跨域安全的时候,所有前端post请求时,会发送一个与其请求名字一样的OPTIONS
此请求没有任何参数,此机制为post不知道是否有权限请求接口,发送了一个探知请求,探知
请求确认后,允许访问后调用正常Post接口。 不允许就会出现你现在的问题跨域异常。
萌新,java是开源的,比NET好多了,多看看底层
前言
相信大家在写前端脚本的时候经常会遇到发送数据到后台的情况,但是由于浏览器的限制,不同域名之间的数据是不能互相访问的,那前端怎么和后端如何进行数据之间的交换呢?
JavaScript由于安全性方面的考虑,不允许页面跨域调用其他页面的对象,那么问题来了,什么是跨域问题?
答:这是由于浏览器同源策略的限制,现在所有支持JavaScript的浏览器都使用了这个策略。那么什么是同源呢?所谓的同源是指三个方面“相同”:
域名相同
协议相同
端口相同
下面就举几个例子来帮助更好的理解同源策略。
URL
说明
是否允许通信
同一域名 允许
不同域名 不允许
同一域名不同端口 不允许
同一域名不同协议 不允许
在JAVA中处理跨域问题,通常有以下两种常用的解决方法。
第一种解决方法
后台代码在被请求的Servlet中添加Header设置:
response.setHeader("Access-Control-Allow-Origin", "*");
PrintWriter out =null;
try
{
out = response.getWriter();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
out.print("{'status':'ok'}");
out.flush();
out.close();
Access-Control-Allow-Origin这个Header在W3C标准里用来检查该跨域请求是否可以被通过,如果值为*则表明当前页面可以跨域访问。默认的情况下是不允许的。
在前端JS中需要向Servlet发出请求,请求代码如下所示:
$.ajax({
url: "your url",
type:"get or post",
dataType:"json",
data:{
....
},
success:function(data){
...
}
第二种解决方法
通过jsonp跨域请求的方式。JSONP和JSON虽然只有一个字母的区别,但是他们完全就是两回事,很多人很容易把他们搞混。JSON是一种数据交换的格式,而JSONP则是一种非官方跨域数据交互协议。
首先来说一下前端JS是怎么发送请求。代码如下所示:
$.ajax({
url:"your url",
type:"get or post",
async:false,
dataType : "jsonp",
//服务端用于接收callback调用的function名的参数
jsonp:"callbackparam",
//callback的function名称
jsonpCallback:"success_jsonpCallback",
success:function(data){
console.log(data);
},
error:function(data){
console.log(data);
}
});
这里的callbackparam和success_jsonpCallback可以理解为发送的data数据的键值对,可以自定义,但是callbackparam需要和后台约定好参数名称,因为后台需要获取到这个参数里面的值(即success_jsonpCallback)。
下面,最重要的来了,后台怎么样获取和返回数据呢。代码如下所示:
PrintWriter out =null;
String callback=req.getParameter("callbackparam");
String json=callback+"({'status':'ok'})";
try
{
out = resp.getWriter();
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
out.print(json);
out.flush();
out.close();
首先需要获取参数名为callbackparam的值,这里获取到的值就是“success_jsonpCallback”。然后将这个值加上一对小括号。小括号里放入你需要返回的数据内容,比如这里我返回一个JSON对象。当然你也可以返回其他对象,比如只返回一个字符串类型数据也可以。最后前端JS返回的数据就是这样的:
success_jsonpCallback({'status':'ok'})
浏览器会自动解析为json对象,这时候你只需要在success回调函数中直接用data.status就可以了。
一句话:同一个ip、同一个网络协议、同一个端口,三者都满足就是同一个域,否则就是跨域。
基于两个方面:
a. web应用本身是部署在不同的服务器上
b.基于开发的角度 --- 前后端分离
web应用本身是部署在不同的服务器上,对应的域名也就有所不同
比如百度。
主域名:
二级域名:, ,
需要在不同的域之间,通过ajax方式互相请求,是非常常见的需求。
Spring 4中增加了对jsonp的原生支持,只需要ControllerAdvice就可以开启,方法如下:
首先新建一个Advice类,我们叫做“JsonpAdvice”,然后在里面定义接收jsonp请求的参数key:
@ControllerAdvice("cn.isy.web.sso.web")指定作用的包名
supper("callback")指定的是url中callback:
注意:
我们还可以重写AbstractJsonpResponseBodyAdvice中的feforeBodyWriteInternal方法:
做到实现url携带callback就返回jsonp格式,没有就返回正常格式
img
controller中
controller中的代码正常编写就OK,不用修改任何东西。
只要保证在cn.isy.web.sso.web包下即可!
jquery ajax
注意:必须使用jsonp的方式提交请求!
有关cors的介绍可以去详细看一下,这里就不作重复了:
CORS详解
跨资源共享CORS详解
主要配置
使用注解CrossOrigin
在controller类上添加CrossOrigin注解表示当前类中的所有入口函数都
可以实现跨域。也可以指定某个conroller中具体的方法。
img
了解一下这个注解的内容:
img
jquery ajax的写法
注意:这里不用使用jsonp的方式请求普通的ajax即可!,因为浏览器自己可以去做!
CORS全局配置
自己试了试没有成功!
资料
解释cors的原理不错
让自己变得更优秀才可以有更多资源
搜索微信号(ID:芋道源码),可以获得各种 Java 源码解析。
并且,回复【书籍】后,可以领取笔者推荐的各种 Java 从入门到架构的书籍。