AJAX跨域访问
谈到js跨域访问,首先要了解的一个概念,就是同源策略。所谓同源是指域名、协议、端口相同。不同源的客户端脚本(javascript、ActionScritp)在没明确授权的情况下,不能读写对方的资源。简单的来说,就是浏览器仅允许包含在A页面的脚本访问与他同域名下的页面或者服务器资源(如service,action,servlet,js脚本等),不同域名下的脚本不能互相访问,即便是子域也不行。它是由Netscapte提出的一个著名的安全策略,现在所有的支持JavaScript的浏览器都会使用这个策略。 如果我们需要不同域名下的脚本互相访问的话,由于同源策略的限制,直接访问肯定不行。这样,就涉及到了跨域访问的问题。如何解决跨域访问问题呢?这里提供三个方案。
JSONP方式实现跨域请求 JSONP工作原理:由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。若要跨域请求出于安全性的考虑是不行的。但是我们发现,Web页面上调用js文件时则不受是否跨域的影响,而且拥有“src”这个属性的标签都具有跨域的能力,比如<script>、<img>、<iframe>。如果通过使用html的script标记来进行跨域请求,并在响应中返回要执行的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,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://www.52php.cn/article/p-ssnpnhce-sq.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |