如何解决ajax跨域的问题? ajax跨域调用的解决办法有很多种!

[ 4130 查看 / 2 回复 ]

解决ajax跨域的问题 ajax跨域调用的解决办法有很多种,我这里只说两种: 假设s.cnblogs.com是一个评论系统,只提供javascript方式的调用。news.cnblogs.com是一个新闻系统,这个系统将评论功能委托给s.cnblogs.com。这时news.cnblogs.com发表评论的代码可能是: function sendData(data,callback) { var xmlHttp=createXmlHttpRequest(); xmlHttp.open('post','http://s.cnblogs.com/postHandler.ashx'); xmlHttp.onreadystatechange=callback; xmlHttp.send(data);//data包含要发送的数据。 } 这代代码在IE6中会有一个安全提醒,但在IE7里面,直接会出错。因为跨域。 第一种解决方案:document.domain. 1.将sendData代码存进一个services.htm文件中。并在services.htm中设置document.domain='cnblogs.com' 2.将services.htm放到s.cnblogs.com网站根目录下面。 3.在news.cnblogs.com提交评论的页面加上<iframe id='ajaxFrame' src='http://s.cnblogs.com/services.htm' width='0' height='0'></iframe> 4.在news.cnblogs.com提交评论的页面加上 function sendData(data,callback) {     ajaxFrame.window.sendData(data,callback); } 和document.domain='cnblogs.com'; 方案的缺点: 只能解决跨子域的问题。 方案2:动态script 法。 1.在news.cnblogs.com提交评论的页面加上,<script id='ajaxProxy' src=''></script> function sendData(data,callback) {     var proxy=document.getElementById('ajaxProxy');     proxy.src='http://s.cnblogs.com/postHandler.ashx?data="+data;     proxy.onreadystatechange=callback; } 我个人更喜欢方案2,但方案的一个问题是callback可以做的事情太少,无法接收postHandler.ashx发回的所馈数据。 不过,我觉得有一种变通的方案,那就是直接在postHandler.ashx中输出js,比如alert('ok');,但我测试了几次都没能成功能。感觉可能是我的RP问题。 这都不是完美的解决方案,用本地代理才是终极方案! Ajax跨域访问的问题 出于安全性考虑,浏览器禁止ajax跨域访问,但当有遇到这一类需求时就直接否则ajax直接访问这一方法。 当然方法一定是有的,在网上一搜能找到一堆解决方案,如动态创建iframe获取结果在传回处理的,或者用script的src属性绕过的,还有通过本地代理的,我感觉本地代理方式是一种比较完美的方法,直接通过ajax像本地服务请求,本地服务再向远程服务获取结果,然后传回客户端,当然多了中间一层代理,但过程还是ajax方式的,同时本地的 service可以任意处理出想要的结果。 上回说到使用jQuery跨域调用JSON数据,但是如果对方不提供JSON数据,则需要用另外的方法实现跨域调用。这两天遇到这个问题,查了些资料,有一种基于代理的方式实现跨域调用。 基本解决思路是,在本域写一个程序向对方发起请求,并且将响应内容再输出。这个程序相当于一个代理,则跨域调用就可以变成对本域的调用了。 我用php实现的代理程序如下: 1 2 $remoteURL=urlencode($url); echo get_file_contents($remoteURL); 要注意的是,使用urlencode需要在php.ini中开启allow_url_fopen。
分享 转发
TOP

回复: 如何解决ajax跨域的问题? ajax跨域调用的解决办法有很多种!

业务场景: 跨域的融合应用,企业内网的自动化办公应用与放置在公网上的应用集成 流程:

1、用户通过浏览器登陆集成的门户

2、集成的门户返回页面,用户选择外域提供的功能链接

3、链接发送到跨域接口模块

4、跨域接口模块解密藏在cookie中的集成门户颁发的登陆票,获取userid,跨域接口模块生成一个重定向到外域应用门户网页,并将用户ID及本域服务器身份认证信息放置到自动提交的隐藏表单中。隐藏表单的提交地址是外域的页面地址

5、跨域接口模块把网页返回给浏览器,浏览器自动提交隐藏表单,请求发送外域WEB服务器。外域服务器登陆用户。

特点:

1、后续请求不过跨域接口模块,直接与外域WEB服务器连接

2、对同一个用户,本域WEB服务器与外域WEB服务器维护的是独立的两个COOKIE,有独立的超时时间。本域应用用户logout后,外域应用会话有可能还存活。

3、基于安全考虑,本域的传递到外域服务器的信息可以进行加密。

TOP

回复: 如何解决ajax跨域的问题? ajax跨域调用的解决办法有很多种!

Javascript跨域和Ajax跨域解决方案
  最近做的一个项目中需要ajax跨域取得数据,如果是在本域中确实没有问题,但是放到二级域和其他域下浏览器直接就弹出提示框:“该页正在访问其控制范围之外的数据,这有些危险,是否继续" 1.什么引起了ajax跨域不能的问题 ajax本身实际上是通过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,不允许js代码进行跨域操作,所以会警告。 2.有什么完美的解决方案么? 没有。解决方案有不少,但是只能是根据自己的实际情况来选择。 具体情况有: 一、本域和子域的相互访问: www.aa.com和book.aa.com 二、本域和其他域的相互访问: www.aa.com和www.bb.com 用 iframe 三、本域和其他域的相互访问: www.aa.com和www.bb.com 用 XMLHttpRequest访问代理 四、本域和其他域的相互访问: www.aa.com和www.bb.com 用 JS创建动态脚本 解决方法: 一、如果想做到数据的交互,那么www.aa.com和book.aa.com必须由你来开发才可以。可以将book.aa.com用iframe添加到 www.aa.com的某个页面下,在www.aa.com和iframe里面都加上document.domain = "aa.com",这样就可以统一域了,可以实现跨域访问。就和平时同一个域中镶嵌iframe一样,直接调用里面的JS就可以了。(这个办法我没有尝试,不过理论可行) 二、当两个域不同时,如果想相互调用,那么同样需要两个域都是由你来开发才可以。用iframe可以实现数据的互相调用。解决方案就是用window.location对象的hash属性。hash属性就是http://domian/web/a.htm#dshakjdhsjka 里面的#dshakjdhsjka。利用JS改变hash值网页不会刷新,可以这样实现通过JS访问hash值来做到通信。不过除了IE之外其他大部分浏览器只要改变hash就会记录历史,你在前进和后退时就需要处理,非常麻烦。不过再做简单的处理时还是可以用的,具体的代码我再下面有下载。大体的过程是页面a和页面b在不同域下,b通过iframe添加到a里,a通过JS修改iframe的hash值,b里面做一个******(因为JS只能修改hash,数据是否改变只能由b自己来判断),检测到b的hash值被修改了,得到修改的值,经过处理返回a需要的值,再来修改a的hash值(这个地方要注意,如果a 本身是那种查询页面的话比如http://domian/web/a.aspx?id=3,在b中直接parent.window.location是无法取得数据的,同样报没有权限的错误,需要a把这个传过来,所以也比较麻烦),同样a里面也要做******,如果hash变化的话就取得返回的数据,再做相应的处理。 三、这种情形是最经常遇到的,也是用的最多的了。就是www.aa.com和www.bb.com你只能修改一个,也就是另外一个是别人的,人家告诉你你要取得数据就访问某某连接参数是什么样子的,最后返回数据是什么格式的。而你需要做的就是在你的域下新建一个网页,让服务器去别人的网站上取得数据,再返回给你。domain1下的a向同域下的GetData.aspx请求数据,GetData.aspx向domain2下的 ResponseData.aspx发送请求,ResponseData.aspx返回数据给GetData.aspx, GetData.aspx再返回给a,这样就完成了一次数据请求。GetData.aspx在其中充当了代理的作用。具体可以看下我的代码。 四、这个和上个的区别就是请求是使用<script>标签来请求的,这个要求也是两个域都是由你来开发才行。原理就是JS文件注入,在本域内的a 内生成一个JS标签,它的SRC指向请求的另外一个域的某个页面b,b返回数据即可,可以直接返回JS的代码。因为script的src属性是可以跨域的。具体看代码,这个也比较简单。 [size=+0]总结: 第一种情况:域和子域的问题,可以完全解决交互。 第二种情况:跨域,实现过程非常麻烦,需要两个域开发者都能控制,适用于简单交互。 第三种情况:跨域,开发者只控制一个域即可,实现过程需要增加代理取得数据,是常用的方式。 第四种情况:跨域,两个域开发者都需要控制,返回一段js代码。 =================== A域有页面a.html,其中有iframe包含B域的页面b.html,现在要通过a.html上的一个按钮,来把a.html页面上一个文本框的值传递到b.html页面的文本框。 注:这里b.html是html网页,不能接收其他网站post过来的值,所以不能用直接post的方法来传值,但是,如果接收页面是b.aspx或者b.asp 呢,那不是可以直接post了么?答案是肯定的,确实可以,但是b.asp或b.aspx必须要刷新,才可以,如何能不刷新的动态改变接收页的元素或者值呢?(IE的本地项目是可以实现跨域访问的,但是外网的跨域访问默认是被拒绝的。FireFox本地项目以及外网的跨域访问都是被拒绝的。) 原理: 浏览器禁止跨域数据访问,但是浏览器并没有禁止跨域跨框架的post传值。我们可以在A域,post到B域的某个页面的框架中,然后通过B域的框架页来实现本域内的数据访问。这其实是html应用中的一个小技巧,并没有用到其他高深的知识就实现了跨域的数据提交。 方法: 在B域中添加两个页面,来实现跨域的数据访问,post.aspx和main.aspx。 页面关系如下,A域的a.html包含一个框架,框架页地址是B域的main.aspx,main.aspx是一个框架集包含两个框架,(frmMain)b.html 和(frmPost)post.aspx. A域的a.html: <form action="http://www.b**.com/post.aspx" method="post" target="frmPost"> <input id="cmd" type="text" size="20"> <input type="submit"> </form> <iframe src="http://www.b**.com/main.aspx"></iframe> B域的main.aspx: <frameset rows="*,0" frameborder="no" border="0" framespacing="0"> <frame src="b.html" name="frmMain"> <frame src="post.aspx" name="frmPost"> </frameset> 我们先把要传递到B域的数据保存到a.html的form中,然后post到B域的post.aspx. 这时post.aspx接收到值,然后执行本域内的父框架访问b.html。 string cmd = Request.Form["cmd"]; if (null != cmd && string.Empty != cmd) {         Response.Write("<script language=\"JavaScript\" for=\"window\" event=\"onload\"> if (parent && parent.frames[\"frmMain\"]) { 这里添加控制b.html的执行代码} </script> "); } 不难发现,这里利用跳跃跨frame(即中间跃过了一层frame)的方法,来实现跨域的数据访问。即post到frame的子frame里面。 后记: 这个例子不过是一些特殊的情况下跨域访问的解决方案,也许对你会有所帮助。因为方法简单,应用也就有很多局限性。(不过偶倒是觉得这样很象ajax哦,页面没有刷新,同样完成了一次服务端的数据处理^o^)。 相关网文资料: web应用的跨域访问解决方案 做过跨越多个网站的Ajax开发的朋友都知道,如果在A网站中,我们希望使用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。Ajax的跨域访问问题是现有的Ajax开发人员比较常遇到的问题。 IE对于跨域访问的处理是,弹出警告框,提醒用户。如果用户将该网站纳入可信任网站,或者调低安全级别,那么这个问题IE就不会在提醒你。 FireFox等其它非微软的浏览器遇到跨域访问,则解决方案统一是拒绝访问。 有人说,IE是主流浏览器,只要它能正常使用就好了。此言差已,IE虽然能够处理,但是是有前提的,要么用户不厌其烦地在页面弹出警告框之后点击是(点击否就不执行该Ajax调用了),要么用户将该网站纳入可信任站点。这两种做法,在企业管理系统的应用中倒是比较常见,因为系统管理员可以以行政手段保证用户的行为。但是对于互联网上的网站或者门户开发,这种做法则不行。 最近遇到了这个问题,需要在跨域访问结束之后完成使主窗口出现一些特效,搜索了一些资料,通过不断尝试以及在不同浏览器中进行兼容性测试,找到了几个可行的方案: 1、Web代理的方式。即用户访问A网站时所产生的对B网站的跨域访问请求均提交到A网站的指定页面,由该页面代替用户页面完成交互,从而返回合适的结果。此方案可以解决现阶段所能够想到的多数跨域访问问题,但要求A网站提供Web代理的支持,因此A网站与B网站之间必须是紧密协作的,且每次交互过程,A网站的服务器负担增加,且无法代用户保存session状态。 2、on-Demand方式。MYMSN的门户就用的这种方式,不过MYMSN中不涉及跨域访问问题。动态控制script标记的生成,通过修改script标记的src属性完成对跨域页面的调用。此方案存在的缺陷是,script的src属性完成该调用时采取的方式时get方式,如果请求时传递的字符串过大时,可能会无法正常运行。不过此方案非常适合聚合类门户使用。 3、iframe方式。查看过醒来在javaeye上的一篇关于跨域访问的帖子,他提到自己已经用iframe的方式解决了跨域访问问题。数据提交跟获取,采用iframe这种方式的确可以了,但由于父窗口与子窗口之间不能交互(跨域访问的情况下,这种交互被拒绝),因此无法完成对父窗口效果的影响。 (偶找到了该文,补充一下地址:http://www.javaeye.com/topic/15641) 4、用户本地转储方式:IE本身依附于windows平台的特性为我们提供了一种基于iframe,利用内存来“绕行”的方案,即两个window之间可以在客户端通过windows剪贴板的方式进行数据传输,只需要在接受数据的一方设置Interval进行轮询,获得结果后清除Interval即可。FF的平台独立性决定了它不支持剪贴板这种方式,而以往版本的FF中存在的插件漏洞又被fixed了,所以FF无法通过内存来完成暗渡陈仓。而由于文件操作FF也没有提供支持(无法通过Cookie跨域完成数据传递),致使这种技巧性的方式只能在IE中使用。 5、我自己用于解决这类问题的方式:结合了前面几种方式,在访问A网站时,先请求B网站完成数据处理,再根据返回的标识来获得所需的结果。这种方法的缺点也很明显,B网站的负载增大了。优点,对session也实现了保持,同时A网站与B网站页面间的交互能力增强了。最重要的一点,这种方案满足了我的全部需要。 总结一下,以上方案中可选择的情况下,我最推荐on-Demand方式,在不需要提交大量数据的情况下,这种方式能够解决您的大部分问题。 =============================== 本地站:http://www.somedomain.com 目标站:http://bbs.somedomain.com 解决方法 : 1. 在目标站 document.domain = 'somedomain.com'; 并建立一个ajax.html,引用ajax方法 (大家都叫它服务中介) 然后创建一个ajax对象 var webreq = new Ajax(); 2. 在本地站 document.domain = 'somedomain.com'; 用iframe引用目标站的ajax.html. 详细方法: 1. 本地站的一个页面(Test.html) html: <html> <head> <script type='text/javascript'>document.domain='somedomain.com';</script> <script type='text/javascript'> function getAjax() { var spn = document.getElementById('spninfo'); var bbsWin = document.getElementById('ifrWindow').contentWindow; var Ajax = bbsWin.webreq; Ajax.Config.Result = 'TestAjaxCross'; Ajax.Config.returnType = 'Content'; Ajax.ActionPost('http://bbs.somedomain.com/doAjax.aspx',spn); } </script> </head> <body> <span id='spninfo' /> <input type='button' id='ajaxBtn' onclick='getAjax' value='Get' /> </body> <iframe id='ifrWindow' src='http://bbs.somedomain.com/ajax.html' style='display:none;'></iframe> </html> ///////////////////////////////////////////////////////////////////////////// 2. 目标站的ajax.html Html: <html> <head> <script type='text/javascript'>document.domain='somedomain.com';</script> <script type='text/javascript' scr='http://bbs.somedomain.com/ajaxMethod.js'></script> <script type='text/javascript'>var webreq = new Ajax();</script> </head> <body> </body> </html> ---------------------------------------------------------------- 目标站: doAjax.aspx html为空 doAjax.aspx.cs 代码(Page_Load) Response.Write("<zwd><content>看到效果了么?</content></zwd>"); return; ===================================================== AjaxMethod.js 代码 ////////////////////Ajax////////////Class/////////////////// //Power By Gloot CopyRight @2006 //Edit Section //Blog http://blog.sina.com.cn/tecz //QQ 345268267 /////////////////////////////////////////////////////////// var Try = { these: function() { var returnValue; for (var i = 0; i < arguments.length; i++) { var lambda = arguments; try { returnValue = lambda(); break; } catch (e) {} } //alert(123); return returnValue; } } function grr(rp) { if(RegExp.$1)/(.*)/.exec(""); var re=new RegExp("<result>(.*)<\/result>"); re.exec(rp); if(RegExp.$1) return RegExp.$1; return ""; } function crr(rp) { if(RegExp.$1)/(.*)/.exec(""); var re=new RegExp("<content>(.*)<\/content>"); re.exec(rp); if(RegExp.$1) return RegExp.$1; return ""; } var Ajax = function() {} //var xhr ;这样定义不行 Ajax.prototype.Init = function(){ return Try.these( function() {return new ActiveXObject("Msxml2.XMLHTTP")}, function() {return new ActiveXObject("Microsoft.XMLHTTP")}, function() {return new XMLHttpRequest()} ) || false; } Ajax.prototype.Config = { Result:"", SucInfo:"", FaildInfo:"", Url:"", returnType:"Compare", //输入Compare是比较返回的字符是否一致,要指定Result值,//其他返回内容 ExecFuncunction(ty){ if (typeof ExecResult == 'function') ExecResult(ty); }, sendData:"" } var aj = new Ajax(); Ajax.prototype.Action = function(url) { //同步 url = url + '&e='+Math.random(); var xhr = aj.Init(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { aj.FuncResult(aj.Config.Spn,xhr); } } } xhr.open("POST",url,false); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xhr.send(null); } Ajax.prototype.Actionfor = function(url,spn) { //异步 url = url + '&e='+Math.random(); var xhr = aj.Init(); //这样写是为了多异步执行 xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { aj.FuncResult(spn,xhr); } } } xhr.open("GET",url,true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xhr.send(null); } Ajax.prototype.ActionAlert = function(url) //执行alert提示框的同步 { url = url + '&e='+Math.random(); var xhr = aj.Init(); //这样写是为了多异步执行 xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { aj.AlertResult(xhr); } } } xhr.open("GET",url,false); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xhr.send(null); } Ajax.prototype.ActionPost = function(url,spn) //同步 send { url = url + '?e='+Math.random(); var xhr = aj.Init(); //这样写是为了多异步执行 xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { aj.postResult(spn,xhr); } } } try { if (netscape.security.PrivilegeManager.enablePrivilege) { netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead'); netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); } }catch(e) {}; xhr.open("POST",url,true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //xhr.setRequestHeader("Content-Length",pars.length); xhr.setRequestHeader("Connection", "open"); xhr.send(Webreq.Config.sendData); } Ajax.prototype.GetJSONData = function(url,spn) { url = url + '?e='+Math.random(); var xhr = aj.Init(); //这样写是为了多异步执行 xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { aj.jsonResult(spn,xhr); } } } xhr.open("POST",url,true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //xhr.setRequestHeader("Content-Length",pars.length); xhr.setRequestHeader("Connection", "open"); xhr.send(null); } Ajax.prototype.onResult = function(v) { return v==aj.Config.Result; } Ajax.prototype.FuncResult = function(spn,xhr) { //alert(spn.id); if (aj.Config.returnType == 'Compare') { if (aj.onResult(grr(xhr.responseText))) { spn.innerHTML = aj.Config.SucInfo; aj.Config.ExecFunc(aj.Config.Result); if (aj.Config.Url!='') { window.location.href = aj.Config.Url; } } else { spn.innerHTML = aj.Config.FaildInfo; } } else { spn.innerHTML = crr(xhr.responseText); aj.Config.ExecFunc(aj.Config.Result); } } Ajax.prototype.AlertResult = function(xhr) { if (aj.Config.returnType=='Compare') { if (aj.onResult(grr(xhr.responseText))) { alert(aj.Config.SucInfo); aj.Config.ExecFunc(aj.Config.Result); } else { alert(aj.Config.FaildInfo); } } else { alert(crr(xhr.responseText)); aj.Config.ExecFunc(aj.Config.Result); } } Ajax.prototype.postResult = function(spn,xhr) { if (aj.Config.returnType == 'Compare') { if (aj.onResult(grr(xhr.responseText))) { spn.innerHTML = aj.Config.SucInfo; aj.Config.ExecFunc(aj.Config.Result); } else { spn.innerHTML = aj.Config.FaildInfo; } } else { spn.innerHTML = crr(xhr.responseText); aj.Config.ExecFunc(aj.Config.Result); } } Ajax.prototype.jsonResult = function(spn,xhr) { var jsonstr = xhr.responseText; var json = eval("return " + jsonstr); //get data json.something json:{username:"123",content:""}; aj.Config.ExecFunc(aj.Config.Result); } /////////////////////////////////////////////////////////////// var WebServices = function() {} WebServices.Config = { }
TOP

关于我们 - 服务条款 - 友情链接 - 诚聘英才 - 服务咨询 - 付款方式 - 联系我们
Copyright(c) 2008 赛门国际商贸网 Inc. All Rights Reserved.  
赛门国际全球站点:    国际站点  |  中国站点

返顶部