跨域主要分为ajax跨域和iframe跨域:
ajax跨域:在一个window中请求另一个项目的数据,域名发生改变,即为ajax跨域。要支持ajax跨域有几种方式,如:jsonp,CORS等。这里主要介绍CORS方式。
iframe跨域:iframe本身是支持跨域的,即在一个域名下的window支持请求另一个域名下的数据显示到iframe,而不会产生跨域问题。但此跨域iframe中不允许访问父window中的属性和函数。即parent.var和top.var和parent.fn和top.fn会出现跨域异常,此时主要解决的是跨域数据传输问题。
CORS跨域:
CORS跨域的主要思想是自定义HTTP响应头从而让浏览器和跨域服务器通信。默认情况下跨域访问时在ajax和http协议中都是不被支持的,为啦支持跨域ajax跨域,请求和响应都必须设置跨域支持参数。
请求参数:使用jquery时设置crossDomain:true,如果要携带cookie需增加参数xhrFields: {withCredentials: true}。则请求格式为:
1 $.ajax({ 2 crossDomain:true, 3 xhrFields: { 4 withCredentials: true 5 }, 6 url:url, 7 data : data, 8 success: function(data, statusText, xhr){ 9 10 } 11 });
响应参数:响应时浏览器接收响应的响应头的响应域名与当前域名不一致,也是不被接受的,会报跨域异常,除非响应头中包含该域名的访问控制允许的参数
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://fsp1.uce.cn:8005");
如果要允许跨域携带cookie,设置响应头Access-Control-Allow-Credentials属性为true
response.setHeader("Access-Control-Allow-Credentials", "true");
为了统一响应参数,不用在每个controller中设置响应头。一般通过Filter实现响应头的统一处理
1 import java.io.IOException; 2 3 import javax.servlet.Filter; 4 import javax.servlet.FilterChain; 5 import javax.servlet.FilterConfig; 6 import javax.servlet.ServletException; 7 import javax.servlet.ServletRequest; 8 import javax.servlet.ServletResponse; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class AccessFilter implements Filter { 12 13 @Override 14 public void init(FilterConfig filterConfig) throws ServletException { 15 16 } 17 18 @Override 19 public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException { 20 21 HttpServletResponse response = (HttpServletResponse) res; 22 response.setHeader("Access-Control-Allow-Origin", "http://fsp1.uce.cn:8005"); 23 response.setHeader("Access-Control-Allow-Credentials", "true"); 24 /*response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); 25 response.setHeader("Access-Control-Max-Age", "3600"); 26 response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); */ 27 chain.doFilter(req, res); 28 } 29 30 @Override 31 public void destroy() { 32 33 } 34 35 }
这样ajax请求就实现啦可带cookie的跨域交互。
iframe跨域:iframe原生支持跨域。跨域iframe主要难在和父窗口进行数据交互。
父窗口向跨域iframe传输数据:主要分为postMessage和window.name,postMessage只能在窗口加载完成后才能使用,如果是固定的iframe标签,可直接获取iframe.postMessage,如果是动态添加的iframe必须监听iframe的load事件,在该事件中postMessage。window.name当然也必须在window存在后才能设置,也要设置在iframe的load事件中,但window.name属性有个特点是只要window存在,doument重新roload的时候,window.name是不变的,因此,对于要在iframe加载过程中使用的数据,我们可以先让iframe的window load一次,此次load是一个空白页面,当空白页面load完成事件设置window.name属性,在设置window.name属性后再修改iframe的src让此window重新加载目标跨域页面,这时在该跨域页面加载过程中就个通过window.name获取到父页面传输的数据。
主要有两种情况:
1>传输的数据在此跨域iframe加载完成后内部触发事件时使用,可通过postMessage传输,此方法较为简单
var state = 1;
document.getElementById('#iframeId').addEventListener("load", function() { if(state == 1) { state = 0; this.contentWindow.postMessage(data,crossDomain) } }, true);
2>传输的数据在此跨域iframe加载过程中调用,此时不能在使用postMessage,该方法只能执行于窗口加载完成后,即load事件后,但在加载过程中如果获取参数,该参数还未传递过来,此时必须使用window.name传递,window的name属性在窗口重新加载内容的时候是不会改变的,最大支持2M。既然要在窗口load时就要读取参数,那么该参数必须要在窗口load之前设置进去,所以要首先load一次窗口,此次load的url为一空白中间页面,目的只是让window加载并且设置window.name属性,在设置之后改变iframe的url为我们的目标跨域url,则iframe从新出发load事件,此时load的过程中就可以获取上次load中间页面设置的window.name属性就获取到了父窗口的值
跨域iframe向父窗口传递数据“
此时iframe已经加载完成,使用postMessage比较方便,父窗口监听跨域iframe的messge,进行相应的处理,比如调用自身的函数
window.onload = function() {
if(window.top == window.self) {
//当前窗口为最顶层窗口
return;
} else {
//折叠消息面板
document.body.onclick = function(event) {
//如果直接调用父页面成功,则直接调用,如果调用失败则为跨域,向父页面传递消息
try {
if(window.top.vm.settings.type) {
window.top.vm.openSetting(event);
}
} catch(e) {
window.top.postMessage('click', '*');
}
}
//皮肤设置
var settings = localStorage.settings;
var themes = settings ? JSON.parse(settings) : {
themes: "default"
}
var css = document.createElement('style');
css.type = 'text/css';
css.id = "themes-setting";
if(themes.themes == 'default') {
css.innerHTML = ".iconfont{color:#ff9372;}";
} else if(themes.themes == 'blue') {
css.innerHTML = ".iconfont{color:#23b7e5;}";
} else {
css.innerHTML = ".iconfont{color:#464c5b;}";
}
document.head.appendChild(css);
}
}
/**
* 监听跨域iframe传递的消息
*/
window.addEventListener('message', function(e) {
var operate = e.data;
switch(operate) {
case 'click':
debugger
if(vm.settings.type){
vm.openSetting();
}
break;
default:
break;
}
})