微服务开启CORS踩的坑

2,511 阅读2分钟

CORS(跨域)工作原理

详细介绍参考:

总结起来就是:当浏览器发起 ajax 请求时,如果目标服务器和当前页面不在同一个域名下,那么将无法访问。
如果要支持跨域调用,那么需要浏览器和服务器同时配合:

  • 浏览器请求时添加请求头
    • Origin 跨域请求的原始域
    • Access-Control-Request-Method 跨域请求的方式(如GET/POST)
    • Access-Control-Request-Headers 跨域请求的请求头信息

浏览器发起跨域请求时,会自动添加请求头,不需要手动处理。

  • 服务器返回时添加响应头
    • Access-Control-Allow-Origin 允许跨域请求的原始域
    • Access-Control-Allow-Credentials 是否允许客户端获取用户凭据(布尔类型)
    • Access-Control-Allow-Methods 允许跨域请求的 http 方法(例如只授权GET/POST)
    • Access-Control-Allow-Headers 允许跨域请求的请求头
    • Access-Control-Expose-Headers 表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息)
    • Access-Control-Max-Age 表示预检请求 [Preflight Request] 的最大缓存时间。(预检请求参考前文阮一峰的文章:非简单请求)

浏览器根据服务器的响应头判断是否允许跨域访问。

CORS 实现

SpringBoot
  • 方式1:返回新的CorsFilter
  • 方式2:重写WebMvcConfigurer
  • 方式3:使用注解(@CrossOrigin)
  • 方式4:手工设置响应头(HttpServletResponse )

具体参照前文链接。

Spring Cloud Gateway

在微服务架构下,我们除了可以在每个微服务内单独设置外,还可以在API网关全局设置跨域支持。 在 Spring Cloud Gateway 的yml配置文件添加配置

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedHeaders: "*"
            allowedMethods: "*"
            allowCredentials: true

有一次我们系统需要开启跨域支持,用前文的方式配置完成后,用 postman 测试,无论采用哪种方式配置,竟然都没有响应头返回。在我一度怀疑是 Spring bug 的时候,鬼使神差的在 postman 的加了 Origin 请求头,竟然就好使了。 后来查看了是spring 源码,其内部会先判断当前请求是否跨域请求,只有跨域请求才会执行添加响应头相关的代码逻辑。