持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
什么是跨域(CORS)
首先跨域是由于浏览器的同源策略导致的,那什么是同源策略,同源就是指协议、域名、端口一致,如果这三个中的一个不同的话就会引起跨域问题,比如说 baidu.com:80 中,https就是协议,baidu.com就是域名,80端口。当我们前端发送ajax请求时如果这三个中有一个不同就会出现跨域问题,浏览器就会拦截请求让我们访问不到资源。
当在控制台中报这次错是,就是出现了跨域问题了。
那浏览器为什么要这样做呢,原因是为了让我们的数据更安全,试问如果你能直接获取篡改其他网站的数据,那不整个网站全乱了吗。
解决方案
解决跨域可以前端解决也可以后端解决,因为本人是名Java程序员所以介绍下用Java解决的方法。
- 首先最简单的方法就是使用@CrossOrigin注解,可以直接在controller类上加上整个类中的方法就都支持跨域,也可以在具体的某个方法上加上表示只有这个方法支持。
@RestController
@RequestMapping("order")
@CrossOrigin
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("{orderId}")
@CrossOrigin
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId,
@RequestHeader(value = "Truth", required = false) String Truth,
@RequestHeader(value = "Hello", required = false) String Hello) {
// 根据id查询订单并返回
return orderService.queryOrderById(orderId);
}
}
使用这个注解浏览器发送GET、POST请求就是直接在头信息中加上一个Origin字段,而对于DELETE、PUT请求就要先增加一次Http查询请求。
- 使用过滤器,拦截请求,给请求加上一些头信息。我们知道在spring中拦截器就是加上@WebFilter注解实现Filter。
@WebFilter
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-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, res);
}
- 在分布式微服务中我们需要配置gateway网关,这个里面也可以做到解决跨域
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 跨域报错之前浏览器会发送一个options请求问服务器是否支持跨域,这个就是允许接收options请求
cors-configurations:
'[/**]': # 拦截所有的请求
allowedOrigins: # 允许哪些网站的跨域请求
- "http://127.0.0.1:550"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期,通过之后下次就是在一小时后再检测
总结
这三种方法都是可以解决跨域的,都各自有自己的优点,用注解的方法十分的方便,但他只能最多只能作用到一个类上,需要写多次,并且有些想自定义的配置也无法完成。使用过滤器的方法可以自定义更具体的一些配置,但是代码写的比较多,没有用注解来得快,如果要让一些方法不提供跨域,也要写一堆代码。使用网关这个方式,代码量少,修改也方便,就是微服务里面用的,写一些单体项目用不到网关。
我们常说的约定>配置>代码,既然约定的是不允许跨域,我认为最合适的方式还是用配置来支持跨越。平常我自己使用的一般还是使用注解的方式,如果微服务推荐用网关配置,因为过滤器拦截器他们还有其他的业务,还有他们自己的事要做。