1 跨域
- 跨域:浏览器对于JavaScript的同源策略的限制。
- 跨域情况:
- 域名不同。
- 域名相同,端口不同。
- 二级域名不同。
- 协议不同。
1、跨域问题
- 跨域不一定都会有跨域问题。
- 跨域问题是浏览器对于Ajax请求的一种安全限制:一个页面发起的Ajax请求,只能是与当前页面域名相同的路径,这能有效的阻止跨站攻击。
2、解决跨域问题
- 方式一:JSONP
- 最早的解决方案,利用script标签可以跨域的原理实现。
- 需要服务的支持,只能发起GET请求。
- 方式二:Ngnix反向代理
- 利用Nginx把跨域反向代理为不跨域,支持各种请求方式。
- 需要在Nginx进行额外配置,语义不清晰。不符合devOps思想
- 方式三:CORS
- 规范化的跨域请求解决方案,安全可靠。
- 在服务端进行控制是否允许跨域,可自定义规则。支持各种请求方式。
- 会产生额外的请求。
2 CORS
1、什么是CORS
- CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)。
- 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服Ajax只能同源使用的限制。
- CORS需要浏览器和服务器同时支持。
- 浏览器端:整个CORS通信过程,都是浏览器自动完成,不需要用户参与。
- 服务器端:浏览器会在请求中携带一些头信息,需要以此判断是否允许其跨域,然后在响应头中加入一些信息即可,一般通过过滤器完成。
2、原理
浏览器会将Ajax请求分为两类:简单请求、特殊请求。
简单请求要满足两个条件:
- 请求方法:HEAD、GET、POST。
- 头信息:Accept、Accept-Language、Content-Language(application/x-www-form-urlencoded、multipart/form-data、text/plain)、Last-Event-ID。
当浏览器发现发起的Ajax是简单请求时,会在请求头中携带一个字段:
Origin
,其值为原始域名(协议+域名+端口)。服务器会根据这个值决定是否允许其跨域。如果服务器允许跨域,需要在返回的响应头中携带以下信息:
Access-Control-Allow-Origin: http://manage.leyou.com Access-Control-Allow-Credentials: true Content-type: text/html; charset=utf-8
不符合简单请求的条件,会被浏览器判定为特殊请求。特殊请求会在正式通信之前,增加一次HTTP查询请求,称为“预检”请求。
浏览器会先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
与简单请求相比,除了Origin以外,多了两个头:
Access-Control-Reuqest-Method Access-Control-Request-Headers
服务器收到预检请求,如果许可跨域,会发出响应:
Access-Control-Allow-Origin: http://manage.leyou.com Access-Control-Allow-Credentials: true Content-type: text/html; charset=utf-8 Access-Control-Allow-Methods Access-Control-Allow-Headers Access-Control-Max-Age
3 SpringMVC
SpringMVC中写好了CORS的跨域过滤器:
CorsFilter
。增加配置类(微服务中应该在Zuul网关中配置):
package com.leyou.gateway.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class LeyouCorsConfiguration { @Bean public CorsFilter corsFilter() { // 1、配置CORS跨域信息 CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("http://manage.leyou.com"); // 设置允许跨域的原始域名 corsConfiguration.setAllowCredentials(true); // 允许携带Cookie corsConfiguration.addAllowedMethod("*"); // 允许所有请求方法 corsConfiguration.addAllowedHeader("*"); // 允许所有头信息 // 2、初始化CORS配置源 UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource(); corsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); // 3、返回CORS过滤器 return new CorsFilter(corsConfigurationSource); } }
4 SpringBoot
增加配置类:
package com.example.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @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("*"); } }