AJAX跨域访问

来源:互联网 发布:pl2303hx数据手册 编辑:程序博客网 时间:2024/05/22 10:45

       谈到js跨域访问,首先要了解的一个概念,就是同源策略。所谓同源是指域名、协议、端口相同。不同源的客户端脚本(javascriptActionScritp)在没明确授权的情况下,不能读写对方的资源。简单的来说,就是浏览器仅允许包含在A页面的脚本访问与他同域名下的页面或者服务器资源(如serviceactionservletjs脚本等),不同域名下的脚本不能互相访问,即便是子域也不行。它是由Netscapte提出的一个著名的安全策略,现在所有的支持JavaScript的浏览器都会使用这个策略。

       如果我们需要不同域名下的脚本互相访问的话,由于同源策略的限制,直接访问肯定不行。这样,就涉及到了跨域访问的问题。如何解决跨域访问问题呢?这里提供三个方案。

  •   采用JSONP跨域GET请求是一个常用的解决方案。
  •    用服务端的XmlHttpRequest代理实现跨域访问
  •   基于iframe(一般用于父域子域之间的跨域)

        JSONP方式实现跨域请求        

        JSONP工作原理:由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。若要跨域请求出于安全性的考虑是不行的。但是我们发现,Web页面上调用js文件时则不受是否跨域的影响,而且拥有“src”这个属性的标签都具有跨域的能力,比如<script><img><iframe>。如果通过使用htmlscript标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。即在跨域的服务端生成JSON数据,然后包装成script脚本回传,就突破了同源策略的限制,解决了跨域访问的问题。

       JSONP的缺点:JSONP不提供错误处理。如果动态插入的代码正常运行,你可以得到返回,但是如果失败了,那么什么都不会发生。demo1

     客户端代码

<!DOCTYPE html><html>   <head>      <meta charset="utf-8" />      <title>客户端</title>      <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>      <script type="text/javascript">         function SendData(){            $.ajax({                type:"get",                url:"http://127.0.0.1:8080/WebTest/doTestServer",                dataType:"jsonp",                jsonp:"callback",  //传递给请求处理程序或页面的,用以获得jsonp回调函数名                //的参数名(一般默认为callback)不需要改动                jsonpCallback:"clientreceive",//自定义的jsonp回调函数名称,                //默认为jQuery自动生成的随机函数名,也可以写“?”,jQuery会自动为你处理数据                //执行成功后执行的方法,此方法在clientreceive方法之后执行                success:function(data){                   alert(data.name);                },                error:function(data){                   alert("出错了!");                }            });         }         //将服务端返回的数据封装成相应的js文件         functionclientreceive(data){            alert(data.age);         }      </script>   </head>   <body>      <input type="button" value="提交" onclick="SendData();"/>   </body></html>

        服务端代码:(此demo服务端用servlet实现)

public class testService extends HttpServlet{   @Override   protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)         throws ServletException,IOException {      resp.setContentType("application/json;charset=utf-8");      Stringcallback = req.getParameter("callback");      Stringjson = " ({'name':'张三','age':'20'})";      resp.getWriter().write(callback+ json);//注意此处输出的数据格式   }}


 

       用服务端的XmlHttpRequest代理实现跨域访问

       我们不能在浏览器端直接使用AJAx来跨域访问资源,但是在服务端是没有这种跨域安全限制的。所以,我们只需要让服务器端帮我们完成“跨域访问”的工作,然后在浏览器端用AJAX获取服务端“跨域访问”的结果就可以了。

       客户端js代码

<span style="font-size:14px;">function SendData(){            $.ajax({                type:"get",                url:"doServiceProxy",                success:function(res){                   varsubval=res.substring(res.indexOf("(")); //返回的参数名                   varcallfunc=res.substring(0,res.indexOf("(")); //返回的数值                   var json = (new Function("return "+ subval))(); //转换为json格式                   if($.trim(callfunc)=='clientreceive'){                      clientreceive(json);//调用回调方法,将返回的数值封装成相应的文件                   }                   alert(json.name);                   alert(json.age);                   },                error:function(res){                   alert("失败");                }            });         }          //将服务端返回的数据封装成相应的js文件         functionclientreceive(data){            alert("处理服务端数据");         }</span>

       本地服务端代码(跨域代理)

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader; import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;@SuppressWarnings("deprecation")publicclassserviceproxy extends HttpServlet{   privatestaticfinallongserialVersionUID= -2007067084377015151L;   @Override   protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)         throws ServletException,IOException {      HttpClientclient=newDefaultHttpClient();        HttpGethttpgets=newHttpGet("http://127.0.0.1:8080/WebTest/doTestServer?callback=clientreceive");      HttpResponseresponse=client.execute(httpgets);      HttpEntityentity=response.getEntity();      if(entity!=null){         InputStreaminstreams=entity.getContent();         Stringstr=convertStreamToString(instreams);         resp.getWriter().write(str);      }   }   //将流转换为字符串   publicstatic StringconvertStreamToString(InputStream is){      BufferedReaderreader=newBufferedReader(newInputStreamReader(is));      StringBuildersb=newStringBuilder();      Stringline=null;      try{         while((line=reader.readLine())!=null){            sb.append(line+"\n");         }      }catch(Exception e){         e.printStackTrace();      }finally{         try{            is.close();         }catch(Exception e){            e.printStackTrace();         }      }      return sb.toString();   }   @Override   protectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp)         throws ServletException,IOException {      doGet(req,resp);   }}

        远程服务端(最终要访问的跨域服务端)与demo1服务端代码一致。

          基于iframe实现跨域访问demo(一般用于父域子域之间的跨域)

        基于iframe实现的跨域要求两个域具有aa.xx.com,bb.xx.com这种特点,也就是两个页面必须属于一个基础域(例如都是xxx.com或是xxx.com.cn),使用同一协议(例如都是http)和同一端口,这样在两个页面中同时添加document.domain,就可以实现父页面调用子页面的函数。

       页面一:

<html> <head>  <script>    document.domain = "xx.com";    function aa(){       alert("p");    }   </script>  </head> <body>   <iframe src="http://localhost:8080/CmsUI/2.html"id="i">      </iframe>    <script>      document.getElementById('i').onload = function(){        var d = document.getElementById('i').contentWindow;        d.a();             };    </script>   </body> </html> 

     页面2

<html>  <head>  <script>     document.domain = "xx.com";    function a(){       alert("c");     }   </script>   </head>  <body>  </body> </html> 

 参考资料:http://blog.csdn.net/wangxiaohu__/article/details/7294842

0 0
原创粉丝点击