Javascript跨域和Ajax跨域解决方案(转)

本文探讨了AJAX跨域问题及其多种解决方案,包括子域间及不同域间的访问策略,如使用iframe、XMLHttpRequest代理、动态脚本等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


======================================================
注:本文源代码点此下载
======================================================

code

最近做的一个项目中需要ajax跨域取得数据,如果是在本域中确实没有问题,但是放到二级域和其他域下浏览器直接就弹出提示框:“该页正在访问其控制范围之外的数据,这有些危险,是否继续"

1.什么引起了ajax跨域不能的问题

ajax本身实际上是通过xmlhttprequest对象来进行数据的交互,而浏览器出于安全考虑,不允许js代码进行跨域操作,所以会警告。

2.有什么完美的解决方案么?

没有。解决方案有不少,但是只能是根据自己的实际情况来选择。

具体情况有:

一、本域和子域的相互访问: http://www.aa.com和book.aa.com/

二、本域和其他域的相互访问: http://www.aa.com和www.bb.com/ 用 iframe

三、本域和其他域的相互访问: http://www.aa.com和www.bb.com/ 用 xmlhttprequest访问代理

四、本域和其他域的相互访问: http://www.aa.com和www.bb.com/ 用 js创建动态脚本

解决方法:

一、如果想做到数据的交互,那么http://www.aa.com和book.aa.com/必须由你来开发才可以。可以将book.aa.com用iframe添加到 http://www.aa.com/的某个页面下,在http://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变化的话就取得返回的数据,再做相应的处理。

三、这种情形是最经常遇到的,也是用的最多的了。就是http://www.aa.com和www.bb.com/你只能修改一个,也就是另外一个是别人的,人家告诉你你要取得数据就访问某某连接参数是什么样子的,最后返回数据是什么格式的。而你需要做的就是在你的域下新建一个网页,让服务器去别人的网站上取得数据,再返回给你。domain1下的a向同域下的getdata.aspx请求数据,getdata.aspx向domain2下的 responsedata.aspx发送请求,responsedata.aspx返回数据给getdata.aspx, getdata.aspx再返回给a,这样就完成了一次数据请求。getdata.aspx在其中充当了代理的作用。具体可以看下我的代码。

四、这个和上个的区别就是请求是使用 ");

}

不难发现,这里利用跳跃跨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("看到效果了么?");

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; iarguments.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("(.*)");

re.exec(rp);

if(regexp.$1) return regexp.$1;

return "";

}

function crr(rp) {

if(regexp.$1)/(.*)/.exec("");

var re=new regexp("(.*)");

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 = {

}


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值