跨域问题解决方案(三种)

Same Origin Policy同源策略(SOP)

具有相同的Origin,也即是拥有相同的协议、主机地址以及端口。一旦这三项数据中有一项不同,那么该资源就将被认为是从不同的Origin得来的,进而不被允许访问。

Cross-origin resource sharing跨域资源共享(CORS)

是一个W3C标准。允许浏览器向跨源(协议 + 域名 + 端口)服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持。它的通信过程,都是浏览器自动完成,不需要用户参与。

对于开发者来说,CORS通信与同源的AJAX/Fetch通信没有差别,代码完全一样。

浏览器一旦发现请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

  • 简单请求:只要在头信息增加一个Origin字段。是HEAD、GET、POST请求,并且HTTP的头信息不超出以下几种字段 Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type。反之,就是非简单请求。
  • 非简单请求:在正式通信之前,增加一次OPTIONS查询请求,称为"预检"请求(preflight)。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

实现CORS很简单,就是在服务端加一些响应头,并且这样做对前端来说是无感知的

如果在开发中,发现每次发起请求都是两条,一次OPTIONS,一次正常请求,注意是每次,那么就需要配置Access-Control-Max-Age,避免每次都发出预检请求。

方法一

全局配置,(很多旧版的WebMvcConfigurerAdapter被标记为过时Deprecated)

java 复制代码
@Configuration
public class CorsConfig implements WebMvcConfigurer{
	
	@Override
	public void addCorsMappings(CorsRegistry registry){
		
		registry.addMapping("/**")
			.allowedOrigins("*")
			.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
			.allowCredentials(true)
			.maxAge(3600)
			.allowedHeaders("*");
	}
}

方法二

基于过滤器方式,在response中写入这些响应头。

java 复制代码
@WebFilter(filterName = "CorsFilter")
@Configuration
public class CorsFilter implements Filter{
	
	@Override
	public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException, ServletException {
	
		HttpServletResponse response = (HttpServletResponse)res;
		response.setHeader("Access-Control-Allow-Origin","*");
		response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
	}
}

方法三

@CrossOrigin注解的方式

注解可以放在method、class等上面,类似RequestMapping,也就是说,整个controller下面的方法可以都受控制,也可以单个方法受控制

java 复制代码
public class GoodsController{
	
	@CrossOrigin(origins = "http://localhost:4000")
	@GetMapping("goods-url")
	public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl)throws Exception{
		
	}
}