前后端跨域问题及解决Java版

152 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

什么是跨域(CORS)

首先跨域是由于浏览器的同源策略导致的,那什么是同源策略,同源就是指协议、域名、端口一致,如果这三个中的一个不同的话就会引起跨域问题,比如说 baidu.com:80 中,https就是协议,baidu.com就是域名,80端口。当我们前端发送ajax请求时如果这三个中有一个不同就会出现跨域问题,浏览器就会拦截请求让我们访问不到资源。

image.png 当在控制台中报这次错是,就是出现了跨域问题了。 那浏览器为什么要这样做呢,原因是为了让我们的数据更安全,试问如果你能直接获取篡改其他网站的数据,那不整个网站全乱了吗。

解决方案

解决跨域可以前端解决也可以后端解决,因为本人是名Java程序员所以介绍下用Java解决的方法。

  1. 首先最简单的方法就是使用@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查询请求。

  1. 使用过滤器,拦截请求,给请求加上一些头信息。我们知道在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);  
    }  
  1. 在分布式微服务中我们需要配置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 # 这次跨域检测的有效期,通过之后下次就是在一小时后再检测

总结

这三种方法都是可以解决跨域的,都各自有自己的优点,用注解的方法十分的方便,但他只能最多只能作用到一个类上,需要写多次,并且有些想自定义的配置也无法完成。使用过滤器的方法可以自定义更具体的一些配置,但是代码写的比较多,没有用注解来得快,如果要让一些方法不提供跨域,也要写一堆代码。使用网关这个方式,代码量少,修改也方便,就是微服务里面用的,写一些单体项目用不到网关。

我们常说的约定>配置>代码,既然约定的是不允许跨域,我认为最合适的方式还是用配置来支持跨越。平常我自己使用的一般还是使用注解的方式,如果微服务推荐用网关配置,因为过滤器拦截器他们还有其他的业务,还有他们自己的事要做。