Ajax跨域问题

1、产生跨域的原因

1.1 浏览器限制

1.2 跨域,发出去的请求不是本域的;

在协议、域名、端口任意一个不一样,浏览器就认为是跨域;

1.3 XHR/XMLHttpRequest请求

如果发送的不是XMLHttpRequest请求,就算是跨域,浏览器也不会存在跨域问题;

2、解决思路

2.1 绕过浏览器限制

指定参数,不让浏览器校验即可解决;意义不大,客户端需要改动;

在Chrome启动程序路径下运行如下命令:

chrome —disable-web-security —user-data-dir=g:\temp3

2.2 修改发送的请求类型不是XHR类型 - JSONP

前台发送ajax请求时,修改dataType为jsonp格式;

$.ajax({
	url : url,
	dataType : "jsonp",
	success : function(data) {
		result = data;
	}
});

后台

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
	public JsonpAdvice() {
		super("callback");
	}
}

jsonp发送的是类型是script,返回值类型也是“application/javascript”,并且发送请求时get参数是callback,与后台构造方法中的字符串一致,约定的内容必须一致才可以;

jsonp缺点:a)服务器需要修改代码支持;b)只支持GET请求;c)发送的是js而不是XHR;

2.3 解决跨域问题

2.3.1 被调用方修改代码;

注册并增加过滤器,在response的头文件中添加http允许跨域访问的内容,从而实现跨域访问;

2.3.1.1 服务器端基本实现

注册Filter

@Bean
public FilterRegistrationBean<Filter> registerFilter() {
	FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
	bean.addUrlPatterns("/*");
	bean.setFilter(new CrosFilter());
	return bean ;
}

在响应头文件中添加相应内容

public class CrossFilter implements Filter {
	@Override
	public void destroy() {}
	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain filter)
			throws IOException, ServletException {		
		HttpServletResponse response = (HttpServletResponse) res; 		
		response.addHeader("Access-Control-Allow-Origin", "http://localhost:8081");
		response.addHeader("Access-Control-Allow-Methods", "GET");		
		filter.doFilter(req, response);		
	}
	@Override
	public void init(FilterConfig arg0) throws ServletException {}
}

2.3.1.2 浏览器对于简单请求是先执行后判断;

而对于非简单请求,浏览器先发送OPTIONS预检命令,成功后再发送真正数据;

常见的【简单请求】包括:

    |- 方法为:GET/HEAD/POST

    |- 请求header里面无自定义头

    |-Content-Type为以下几种:

        |- text/plain

        |- multipart/form-data

        |- application/x-www-form-urlencoded

常见的【非简单请求】包括:

    |- PUT/DELETE方法的ajax请求;

    |- 发送json格式的ajax请求;

    |- 带自定义头的ajax请求;

var result;
$.ajax({
	url : base + "/postJson",
	contentType : "application/json;charset=utf-8",
	type : "post",
	data : JSON.stringify({name:"zhangsan"}),
	success : function(json) {
		result = json;
	}
});

非简单请求每次都发送OPTIONS预检命令影响效率,在HTTP协议里增加一个响应头来缓存预检命令:Access-Control-Max-Age对应缓存时间单位是秒;

response.addHeader("Access-Control-Max-Age", "3600");

2.3.1.3 带cookie的跨域

Access-Control-Allow-Origin不能为*,必须是全匹配(完整的域名);

Access-Control-Allow-Origin必须为true;

从request中获取“Origin”,即完整的域名,设置到“Access-Control-Allow-Origin”中;

发送的cookie是被调用方域名的cookie,因为不可能跨域获取cookie;

document.cookie = 'cookie1=lisi'
var result;
$.ajax({
	url : base + "/getCookie",
	type : "get",
	xhrFields:{
		withCredentials:true	
	},
	success : function(json) {
		result = json;
	}
});
String origin = request.getHeader("Origin");
if (!StringUtils.isEmpty(origin)) {
    response.addHeader("Access-Control-Allow-Origin", origin);
}
response.addHeader("Access-Control-Allow-Credentials", "true");

2.3.1.4 带自定义头的跨域

var result;
$.ajax({
	url : base + "/getHeader",
	type : "get",
	headers:{
		"x-header1":"AAA"	
	},
	beforeSend:function(xhr) {
		xhr.setRequestHeader("x-header2","BBB")
	},
	success : function(json) {
		result = json;
	}
});
String origin = request.getHeader("Origin");
if (!StringUtils.isEmpty(origin)) {
	response.addHeader("Access-Control-Allow-Origin", origin);
}
String headers = request.getHeader("Access-Control-Request-Headers");
if (!StringUtils.isEmpty(headers)) {
	response.addHeader("Access-Control-Allow-Headers", headers);
}
response.addHeader("Access-Control-Allow-Methods", "*");

2.3.1.5 Spring框架

注释注册Filter的配置代码,只需要增加@CrossOrigin即可;

如果是带Cookie的跨域,需要添加“allowCredentials="true"”的属性,因为默认配置为false,会报错;

2.3.2 调用方修改代码 - 隐藏跨域;

反向代理:指向同一个域名的不同URL

使用反向代理,把需要跨域调用的接口代理为本域的一个接口,让浏览器认为是调用的本域接口,以实现隐藏跨域;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值