有道词典上对 Gateway 有大门口, 门道, 通道以及计算机术语中的网关之意, 其实对于网关这个概念是很好理解的, 例如有这样高档的小区车库, 当开车经过闸口的时候会识别你的车牌号, 识别成功后会自动将你的车库门打开; 其实计算机中的网关也是如此, 在 Spring Cloud 中网关的实现有两种: Gateway 和 Zuul, 但是 Zuul 是基于 Servlet 实现的, 属于阻塞式编程, 而 Gateway 则是基于 Spring5 中提供的 WebFlux, 属于响应式编程, 具有更良好的性能, 因此我们着重讲的也是比较主流的 Gateway 的使用; 作为 Spring Cloud 的核心组件之一, 主要作用就是统一服务访问的入口, 对所有的微服务进行底层映射, 当客户端访问某一个服务时, 通过服务名来找到相应的服务.
总之网关的作用: 对用户的请求做身份认证及权限的校验; 将用户请求路由到相应的微服务, 并实现负载均衡; 再就是对用户的请求做限流.
Gateway
🐝 Gateway 和 Nginx 的区别
之前的文章中我们学过 Nginx, 它的主要作用是反向代理, 实现负载均衡, 而对于 Gateway 也有实现负载均衡的作用, 负载均衡就是我们将项目部署到多个服务器上, 然后通过使用统一的域名去访问, 如通过 Nginx 对请求进行分发, 从而减轻服务器的压力, 也可以这样说, Nginx 服务器起到了分发的作用, 但是真正的实现可以放在其他的服务器上, Nginx 作为隔离层, 也对我们项目起到了安全壁障. 那么 Gateway 和 Nginx 有什么区别呢?
- 首先要区分这两个概念首先要区分开流量网关和业务网关的概念, Nginx 作为流量网关, 相当于访问的一个总入口, 也就是说我们会将所有的 html 页面放到 Nginx 的容器中, 从而起到流量的监控及日志的管理, 全局的限流等; 而业务网关则是针对具体的后端应用和服务, 也可以总结为 Nginx 主要配置在前端, 而 Gateway 则是配置在后端;
- 其次 Gateway 主要是利用路由, 断言及过滤器进行流量的控制等; Nginx 主要是负载均衡, 反向代理及当做 Web 服务器.
- 总之, Gateway 是前端工程到后端服务器之间的一个业务网关, 而 Nginx 是用户到前端工程的流量网关.
🐝 🐝 Gateway 的作用
- 对用户的请求做身份认证及权限的校验; 网关作为微服务的入口, 需要校验用户是否具有请求的资格, 如果没有则拦截在外面;
- 将用户请求路由到相应的微服务, 并实现负载均衡; 一切请求都必须先经过 Gateway, 但是网关并不处理业务, 这里倒和 Nginx 一致, 而是根据某种规则将请求转发到某个微服务中, 这个过程也称之为是路由; 当然当有多个微服务的时候还需要做负载均衡;
- 对用户的请求做限流; 当客户端的请求流量过多时, 可以在网关中设置微服务能够接受的流量进行放行发过来的请求, 避免服务压力过大.
🐝 🐝 🐝 Gateway 的搭建
步骤一: 创建 Gateway 服务并引入相关依赖;
在 pom.xml 中引入网关及 nacos 服务发现依赖;
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
步骤二: 编写启动类;
步骤三: 在 application.yml 中编写配置及路由规则;
注意 routes 网关路由的配置, id 前面的短线有空格; 路由断言就是来判断请求是否符合规则; uri 中的 lb 即 loadBalance, 也就是负载均衡的意思, providerservice 就是我们的服务名称.
步骤四: 重启测试;
重启服务提供者 / 服务消费者 / Gateway;
网关路由的流程图如下:
🐝 🐝 🐝 🐝 路由
🐝 🐝 🐝 🐝 🙊断言工厂
我们在前面的 yml 中写的断言规则只是字符串, 这些字符串都会被断言工厂读取并处理, 转变为路由判断的条件, 如路径的匹配: - Path=/provider/**
; 关于断言规则还有很多种, 如下图所示, 但是我们常用的也就是 Path 这个了.
总之, 断言工厂(PredicateFactory) 主要作用有就是读取用户定义的断言条件, 对请求做出判断. 如 - Path=/provider/**
代表的含义就是以 /provider 开头的就认为是符合条件的.
🐝 🐝 🐝 🐝 🙊🙊 过滤器
路由过滤器(GatewayFilter) 是网关中提供的一种过滤器, 可以对进入网关的请求和微服务返回的响应进行处理;路由过滤器 spring 也提供了很多种, 如:
案例: 在 providerservice 路由下添加请求头过滤器, 只需要在 yml 文件中的 routes 中添加即可:
过滤器的作用:
- 对路由的请求或者响应做加工处理, 如上面的案例添加请求头;
- filters: 配置在路由下的过滤器只对当前路由的请求生效, default-filters 则是对所有路由都生效.
🐝 🐝 🐝 🐝 🙊🙊🙊 全局过滤器
除了上述方式使用过滤器外, 还有全局过滤器可供我们使用, 它的作用也是处理一切进入网关的请求和微服务的响应, 与上面的过滤器的作用是一样的, 但是不是通过在 yml 中配置使用, 而是需要我们自己写代码实现. 当然接口 spring 中已提供, 如下所示:
案例: 定义一个全局过滤器用来拦截用户并判断其身份; 要求判断请求的参数中是否有 authorization, 并判断其值是否为 admin, 如果都满足这两个条件才放行; 具体实现逻辑如下:
具体实现步骤:
- 实现 GlobalFilter 接口;
- 添加 @Order 注解或者是实现 Ordered 接口;
- 编写处理逻辑.
🐝 🐝 🐝 🐝 🙊🙊🙊🙊过滤器的执行顺序
上面我们已经说了三类过滤器, 当前路由的过滤器 / DefaultFilter 过滤器 / 全局过滤器; 那么请求来了之后, 三者的执行顺序是怎么样的呢?
请求路由后, 会将三个路由器合并到一个过滤器链中, 排序后一次进行执行, 如上图所示;
- 每个过滤器都必须指定一个 int 类型的 order 值, order 值越小, 优先级越高, 执行顺序越靠前;
- 全局过滤器实现 Ordered 接口或者添加 @Order 注解来执行 order 值, 有我们程序猿自己设定;
- 路由过滤器和默认过滤器的 order 是由 Spring 来设定, 默认是按照声明的顺序从 1 递增;
- 当过滤器的 order 值一样时, 会按照 defaultFilter > 默认过滤器 > 全局过滤器的顺序进行执行.
🐝 🐝 🐝 🐝 🐝跨域问题的处理
当域名不同后者是域名相同但是端口号不同时, 浏览器禁止请求的发起者与服务端发生跨域 ajax 请求, 从而请求被浏览器拦截, 遇到这样的问题解决方案可以在 gateway 的 yml 中加入 CORS 配置;