js跨域总结
什么是跨域
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。所谓同源是指,域名,协议,端口均相同。任何一个不同在交流数据时就会产生跨域。
解决方法
1.document.domain + iframe
document.domain是当前网页的域名,如www.abc.com的document.domain=www.abc.com。这个变量可以被赋值,但是只能被赋值为当前域名或者基础域名。如www.abc.com和abc.com。其它赋值都会报错。
如果一个页面用iframe引入另外一个页面,只能看其内容,却不能操作其内容数据。但是如果两个网页的document.domain相同时,是可以互相操作页面内容的。
所以这种跨域的方法是将两个网页中document.domain设置为相同值,这也就决定了这个方法的使用情景,你能够设置两个页面的domian,同时这个设置要符合规定。
2.动态创建script标签
这个方法是利用script的src属性可跨域性质。
直接上例子(网上找的关于登陆判断的例子):
<script>
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;
}
function userLogin(){
var username=document.getElementById('name').value;
var password=document.getElementById('password').value;
var url='http://127.0.0.1:8080/EasyCMS/login.jsp?name='+encodeURI(username)+'&password='+encodeURI(password)+'&s=' + (new Date()).getTime();
//alert("url="+url);
var login=request("loginScript",url);
}
function myloginState(state){
alert("ret:"+state);
if (state==0)
{
alert("登陆成功");
}
else
{
alert("登陆失败");
}
}
</script>
<body>
用户名:<input name="name" id="name" type="text" />
密码:<input name="password" id="password" type="password" />
<input name="" value="login" type="button" onclick="userLogin();" />
</body>
后台代码
String name=request.getParameter("name");
String password=request.getParameter("password");
if (name.equals("admin") && password.equals("admin"))
{
request.getSession().setAttribute("admin","admin");
%>
myloginState("0");
<%
}
else
{
%>
myloginState("1");
<%
}
%>
解读:
前端页面中先定义好了动态创建script标签的方法和获取后台数据后的处理函数。这个动态创建标签的方法是动态创建script标签,同时将url设置为后台接口地址同时拼接页面中的数据,将数据发送至后台。
后台获取传过来的参数根据参数不同返回不同数据。这个数据必须跟前端商量,一般都是一个函数名加上后台获取的数据。因为src标签是代表的替换,所以前端这个标签最终会变成后台返回的语句,执行一个函数。而函数已经在页面中定义好,又获取从后台传过去的数据,从而实现跨域。
也可以将函数名也传至后台,这样后台写法更灵活一些。
3.jsonp
jsonp也是利用script标签的src属性跨域。
举例:
<script type="text/javascript">
function jsonpCallback(result) {
}
}
</script>
<script type="text/javascript" src="http://...?callback=jsonpCallback"></script>
后端代码
$arr=array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
$result=json_encode($arr);
//动态执行回调函数
$callback=$_GET['callback'];
echo $callback."($result)";
解读:
前端页面用script的src将函数名传至后台,后台获取函数名,返回一条包含函数名和参数的语句。前端得到返回值,获取参数,同时执行该函数,实现跨域。
该方法与动态创建script标签基本一样,只不过在需要发送一些页面中的参数时用动态创建script标签,jsonp方法无需传页面中参数,直接写标签即可,也可动态创建。
4.cors跨域
前端代码,在xhr的setRequestHeader方法中设置Origin属性,例:
xhr.setRequestHeader("Origin", "http://www.abc.com")
其中xhr是原生ajax的xhr对象,在jquery中的beforesend方法中可获取原生xhr对象
beforesend:function(xhr){
xhr.setRequestHeader("Origin", "http://www.abc.com")
}
在后台中设置两个属性
Access-Control-Allow-Origin, "http://www.abc.com";
"Access-Control-Allow-Methods, "GET, POST, PUT, DELETE";
//当Access-Control-Allow-Origin设置为"*"时,前端无需设置请求头,可直接访问
5.postmessage
postmessage解决的是两个页面间的跨域通信,比如iframe嵌套页面等。
举例,一个页面通过iframe引用另一个页面。
//获取页面中的iframe
var iframe = document.getElementById('myIFrame').contentWindow;
//注意:contentWindow
iframe.postMessage(message,uri)
//message理论上可以是任何类型的数据,但是不同浏览器对其支持不同,尽量使用字符串,uri是目标uri。
//在iframe中监听message事件
window.addEventListener('message',function(event) {
if(event.origin !== 'http://davidwalsh.name') return;
console.log('message received: ' + event.data,event);
event.source.postMessage('backmessage!',event.origin);
},false);
//event对象中包含很多属性,Origin是信息源域名,在接受信息处理前应判断源。data是接受的数据。sourse是信息源contentWindow的引用。
需要注意的是h5新增方法,注意兼容性。
其它方法
webcosket,window.name+iframe,服务器请求服务器是没有跨域限制的,而且上面集中方法已经涵盖常见的跨域情况,推荐cors,写法简单,前端和后台都无需过多代码。