在部署web应用时,常常会遇到跨域的问题,而spring cloud gateway
作为一个API网关,本身是支持跨域的。这里暂不讨论应不应该开启跨域,只是总结一下:
- 如何开启跨域
- 解决的实际问题
以下这段配置,放到spring cloud gateway
里面,即可开启跨域,放行任何跨域请求
1 | spring: |
不要完全照抄这段代码,搞到你的生产环境里面去,原因请阅读相关文档,先了解跨域资源共享(CORS) 。
什么是跨域资源共享(CORS)
MDN 上有关于CORS 的介绍,地址:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS,这里只放一张图:
解决的实际问题
这里以Pigx(一个微服务框架)Swagger聚合文档的登录验证为例,介绍以下跨域问题出在哪里,以及如何解决。
Pigx是商业级框架,他有一个对应的开源版本:pig 也是相同的技术栈,理论上没有区别。
Swagger 聚合文档
在Pigx微服务框架中,为了统一管理API文档,会将各个微服务模块的API文档聚合到API 网关上,这样就可以通过 http://{GATEWAY-HOST}/swagger-ui.html
来访问。聚合解决了文档分散不好管理和使用的问题。
Swagger 登录认证
使用Swagger不仅仅是为了看接口文档,也是后端开发人员的调试和测试利器,然而,后端的接口一般都是受安全框架保护的,并非裸奔,不能直接调,需要有认证凭据才能具备接口调用的权限,而认证凭据是通过登录操作获取的。也就是说,Swagger得具备一种获取认证凭据的能力,其中一种就是Oauth,这需要配置一个OAuth服务的接口地址:
1 | swagger: |
于是,你通过 http://pigx-gateway:9999/swagger-ui.html
打开swagger界面,然后做登录,登录的请求的AJAX接口是http://pigx-gateway:9999/auth/oauth/token
,成功拿到登录凭据。这个玩法要求你在本地配置host映射,才能满足同源策略,如果想直接使用IP,那就得改配置,实在繁琐。总之,你的swagger页面在浏览器地址栏中的地址和请求token的地址必须满足同源策略。
如果没有满足同源策略,比如pigx-gateway
的真实IP是192.168.0.181
,你直接通过IP打开swagger页面,然后登录就会以为跨域而失败。
分析网络请求,因为触发跨域,浏览器发起了CORS预检请求,然而服务端不支持,返回了错误。
允许部分跨域请求
原有方案的痛点在于:
- 必须配置HOST映射,让后通过主机名访问
swagger-ui
- 实际开发过程中,会有多种部署环境,切换HOST虽然不麻烦,但是也是一件繁琐的事情。
实际上,在开发环境中,安全性也不那么重要,在微服务架构中,认证服务器有时候也会作为边缘网络服务暴露在公网。所以允许认证服务器的请求跨域也不是不可用,至少在开发环境是不存在的。
解决办法
在网关加上下面的配置,允许认证服务器的接口跨域,然后重启网关。
1 | spring: |
这段配置也不是很严谨,开发环境用就可以了
效果测试
不满足同源策略,触发跨域,浏览器发起了CORS预检请求,服务端支持,返回了预检响应。
浏览器检查预检响应后,发起了真正的请求
登录成功
参考资料
2021-02-24 更新
今天pig群里面有小伙伴反应,之前的配置方法不行了,怀疑是pig升级spring cloud 大版本导致的,我测试了一下,仍然有效,测试配置如下
依赖信息(PIG 3.0.5)
1 | <properties> |
1 | spring: |
注意
allowed-origins
不再支持通配符,应该通过allowedOriginPatterns
来设置。DedupeResponseHeader=Access-Control-Allow-Origin
用于head去重,如果你发现网关返回的CORS头里面head值重复,就需要配置,否则不需要。
效果