ajax跨域解决办法

来源:互联网 发布:淘宝优惠券招代理 编辑:程序博客网 时间:2024/05/17 04:54

跨域的安全限制都是指浏览器端来说的.服务器端是不存在跨域安全限制的,

什么是跨域:

跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域

为什么浏览器限制跨域访问呢?

原因就是安全问题:如果一个网页可以随意地访问另外一个网站的资源,那么就有可能在客户完全不知情的情况下出现安全问题。比如下面的操作就有安全问题:

  1. 用户访问www.mybank.com ,登陆并进行网银操作,这时cookie啥的都生成并存放在浏览器
  2. 用户突然想起件事,并迷迷糊糊地访问了一个邪恶的网站 www.xiee.com
  3. 这时该网站就可以在它的页面中,拿到银行的cookie,比如用户名,登陆token等,然后发起对www.mybank.com 的操作。
  4. 如果这时浏览器不予限制,并且银行也没有做响应的安全处理的话,那么用户的信息有可能就这么泄露了。

为什么要跨域

既然有安全问题,那为什么又要跨域呢?有时公司内部有多个不同的子域,比如一个是location.company.com ,而应用是放在app.company.com , 这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。

跨域访问需要的两件宝贝

由于浏览器一般不对script,img等进行跨域限制,所以我们有机会通过script的方式来实现跨域访问。

跨域访问需要用到两样东东,一个是JSON,一种基于文本的传输协议;一种是JSONP,一群码农想出来的跨域解决方案。关于JSON与JSONP的解释,可以参考 JSON & JSONP

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


由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的跨域问题。本篇将讲述一个小白从遇到跨域不知道是跨域问题,到知道是跨域问题不知道如何解决,再到解决跨域问题,最后找到两种方法解决ajax 跨域问题的全过程。

不知是跨域问题

起 因是这样的,为了复用,减少重复开发,单独开发了一个用户权限管理系统,共其他系统获取认证与授权信息,暂且称之为A系统;调用A系统以B为例。在B系统 中用ajax调用A系统系统的接口(数据格式为json),当时特别困惑,在A系统中访问相应的url可正常回返json数据,但是在B系统中使用 ajax请求同样的url则一点儿反应都没有,好像什么都没有发生一样。这样反反复复改来改去好久都没能解决,于是求救同事,提醒可能是ajax跨域问 题,于是就将这个问题当做跨域问题来解决了。

知跨域而不知如何解决

知道问题的确切原因,剩下的就是找到解决问题的方法了。google了好久,再次在同事的指点下知道jQuery的ajax有jsonp这样的属性可以用来解决跨域的问题。

1.第一种解决方式

总结jsonp步骤:

step1:页面

js请求中url请求末尾加callback=?参数。使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。

js返回参数dataType:标明为jsonp

step2:服务器修改

拼旧的返回数据,在外层加callback字符串

这样应该就ok了!

现在也知道了怎样来解决跨域问题,余下的就是实现的细节了。实现的过程中错误还是避免不了的。由于不了解json和jsonp两种格式的区别,也犯了错误,google了好久才解决。

首先来看看在页面中如何使用jQuery的ajax解决跨域问题的简单版:

复制代码
$(document).ready(function(){   var url='http://localhost:8080/WorkGroupManagment/open/getGroupById"       +"?id=1&callback=?';   $.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跨域问题的第一种方式就告一段落。



2.第二种解决方式【通过设置Access-Control-Allow-Origin来实现跨域访问比较简单。】
修改controller在被请求的Response header中加入
在程序中添加


response.addHeader("Access-Control-Allow-Origin","*");//表示允许任何域名跨域访问
如果需要指定某域名才允许跨域访问,
只需把Access-Control-Allow-Origin:*改为Access-Control-Allow-Origin:允许的域名     例如:
response.addHeader('Access-Control-Allow-Origin:http://www.client.com');


@RequestMapping("findCourseNoteByKeywords")@ResponseBodypublic ApiResult findCourseNoteByKeywords(String keyWord,HttpServletResponse response){response.addHeader("Access-Control-Allow-Origin","*");ApiResult apiResult = new ApiResult();List<Map<String, Object>> result = bCourseNoteService.findCourseNotesByKeywords(keyWord);Map map  = new HashMap<String, List<Map<String, Object>> >();map.put("data", result);apiResult.setData(map);return apiResult;}


3.追加一种解决方式

追求永无止境,在google的过程中,无意中发现了一个

专门用来解决跨域问题的jQuery插件-jquery-jsonp。

有第一种方式的基础,使用jsonp插件也就比较简单了,server端代码无需任何改动。

来看一下如何使用jquery-jsonp插件解决跨域问题吧。

复制代码
var url="http://localhost:8080/WorkGroupManagment/open/getGroupById"    +"?id=1&callback=?";$.jsonp({  "url": url,  "success": function(data) {    $("#current-group").text("当前工作组:"+data.result.name);  },  "error": function(d,msg) {    alert("Could not find user "+msg);  }});

SONP方法是一种非官方方法,而且这种方法只支持GET方式,不如POST方式安全。

即使使用jQuery的jsonp方法,type设为POST,也会自动变为GET。

三种方案比较;

方法1需要改动:页面+服务器端代码

方法2需要改动:服务器端代码

方法3需要改动:页面(不过需要引入jquery的插件)

这里针对ajax与jsonp的异同再做一些补充说明: 

1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。

3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变着一点!

1 0
原创粉丝点击