跨域问题总是很难缠,很多时候开发人员都是不自觉间就遇到了跨域,在此晒晒我的解决之道。
1 避免跨域
在最近一个需求中,有一个网页会出现在两个域名下,开始完全没想到这个问题,导致跨域问题产生,出问题代码如下
<form id="form1" method="post" action="http://www.anotherDomain.com/a.htm?_input_charset=UTF-8">
<input type="hidden" name="action" value="SomeAction"/>
<input type="hidden" name="event_submit_do_something" value="true"/>
......
</form>
<script language="javascript">
myAjax = function(){
myhandle = function (hr){
alert(hr.responseText);
}
YAHOO.util.Connect.asyncRequest(
'POST',
FD.common.getFormAction('form1'),
{
success : myhandle,
failure : myhandle,
timeout : 10000
},
FD.common.formSerialize('form1') + '¶m1='+document.getElementById('param1').value
);
}
</script>
修改方案很简单,采用相对路径
<form id="form1" method="post" action="?_input_charset=UTF-8">
这是最简单的办法,因为本身都是一个页面。在公司框架中,这两种写法,程序最终执行的都是SomeAction中doSomething函数,但是程序发送的请求则有所不同,前者发送到了www.anotherDomain下,后者则在当前的域名下,所以跨域问题也就不存在了。
2 采用jsonp方式
如果你还没听过什么是jsonp,可以先看看http://baike.baidu.com/view/2131174.htm?fr=ala0_1
简单说来,就是采用json方式返回数据,和普通json不同的就是将地址写在script的src属性里欺骗浏览器
为了从另外一个域名下的test.html页面取得一个json数据
var ajaxResult={"count":1};
可以在页面的头部添加这样一句即可
<script src="http://www.anotherdomian.com/test.html?param1=$param1" type="text/javascript"></script>
其中的$param1是由服务器的程序生成,所以每次页面打开后其实$param1是不可变的。就是采用这种方式,页面打开后就可以直接使用ajaxResult这个js的变量了,
3 jsonp方式改进
前一种方法如果说还有什么不好的,那可能就是不够动态吧,下面对第2种方式进行改进。
在http://zhidao.baidu.com/ 未登录用户回答问题时会用iframe调用http://zhidao.baidu.com/userlogin.html
userlogin.html有下面的javascript
<SCRIPT LANGUAGE="JavaScript"> document.domain="baidu.com"; <!-- function G(id){if(typeof(id)=="string"){return document.getElementById(id);}return id;} function showInfo(obj){ if(obj.checked == true){ G("memInfo").style.display="block"; }else{ G("memInfo").style.display="none"; } } function request(id,url){ oScript = document.getElementById(id); var head = document.getElementsByTagName("head").item(0); if (oScript) { head.removeChild(oScript); } oScript = document.createElement("script"); oScript.setAttribute("src", url); oScript.setAttribute("id",id); oScript.setAttribute("type","text/javascript"); oScript.setAttribute("language","javascript"); head.appendChild(oScript); return oScript; } var loginTimer=null; var loginState=-1; var tryTime=0; function PSP_ik(isOk){ if(isOk==0){ G("errorInfo").style.display="none"; loginState=1; if(parent.loginSuccess){ parent.Pop.hide(); parent.loginSuccess(); } } else { loginFalse(); } } function loginFalse(){ loginState=0; var err=G("errorInfo"); err.innerHTML="用户名或密码错误,请重新登录"; err.style.display="block"; G("username").focus(); tryTime++; if(tryTime>1){ onLoginFailed(); } } function onLoginFailed(){ if(parent.onLoginFailed){ parent.Pop.hide(); parent.loginFailed(); }else{ document.login.u.value=escape("http://zhidao.baidu.com/q"+parent.location.search); doucment.login.submit(); } } function loginTimeout(){ if(loginState==-1){ var err=G("errorInfo"); err.innerHTML="操作超时,请重新登录"; err.style.display="block"; G("username").focus(); } } function userLogin(){ var username=G('username').value; var password=G('password').value; var memPassport=G('memPassport').checked?"on":"off"; if(username.length<=0||password.length<=0){G("username").focus();return false;} var url = 'https://passport.baidu.com/?logt&tpl=ik&t=0&keyname=ik&mem_pass='+memPassport+'&username='+username + '&loginpass=' +escape(password)+ '&s=' + (new Date()).getTime(); loginState=-1; var login=request("loginScript",url); loginTimer = setTimeout(loginTimeout, 5000); } window.οnlοad=function(){ document.loginForm.username.focus(); document.getElementById("username").focus(); } //--> </SCRIPT>
request方法处理异步请求使用动态往head中添加script而不是用xmlhttp发送get请求。妙就妙在这。我们知道调用javascript是没有域的限制的。当加载完成时一样会执行。
4 通过服务器绕过跨域
将原有的ajax请求,发送到本域名下后台程序,通过后台程序去取得另外一个域名下页面的内容,由于服务器程序不存在跨域的问题,当它得到数据后,再以ajax.responseText返回给原页面,则跨域也可得到解决。
参考文档:
http://baike.baidu.com/view/2131174.htm?fr=ala0_1
http://topic.youkuaiyun.com/u/20081224/09/26aff992-d0ba-4f6f-a023-e0e96ecbe1fc.html