Spring Cloud Gateway 官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-starter
网关主要有以下功能:
用户访问服务流程:
向网关发起请求 —> 网关对请求路径查找匹配的服务 —> 网关对请求进行校验或过滤处理 —> 网关将请求路由到指定服务 —> 服务返回响应给网关 —> 网关将服务响应返回给客户端
SpringCloud 中同类的网关服务还有 zuul,但 zuul 基于 Servlet 实现,属于阻塞式编程。
Gateway 基于 Spring5 中提供的 WebFlux 属于响应式编程,性能更优。
Gateway 服务最后也同时使用服务注册中心,以此实现负载均衡,这里选择阿里的 Nacos
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
只需上面两个依赖即可,spring-cloud-starter-gateway 中包含 spring-web 相关的依赖,可以直接启动服务
启动类不需要特别的配置,示例如下:
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
application.yml 配置文件示例如下:
server:
port: 8088 # 服务端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos 注册中心地址
gateway:
routes: # 服务路由列表
# - 表示列表,同级的 - 添加在同一列表内,id, uri, predicates 组成一个路由,是列表内的一个元素
- id: user-service-route # 路由 id,不可重复
# uri 为目标地址,有两个表示方法
# uri: http://localhost:8082 # 指定固定 ip,无负载均衡
uri: lb://user-service # 指定注册中心的服务名称,通过负载均衡发送请求
predicates: # 断言规则
- Path=/user/** # 匹配以 /user 为开头的请求路径,将其路由到 user-service
现在已经可以启动网关服务了,前提是要先启动 Nacos
启动网关后,客户端访问网关即可,如 localhost:8088/user/1,网关会匹配到 user-service 路由,并将请求路由到从 Nacos 注册中心得到的 user-service 服务
predicates 即为断言,用来判断当前请求是否与服务得路由规则匹配
有多个断言规则存在时,必须全部符合规则,请求才会被路由转发
在上面得例子中用到了 - Path,表示对请求路径进行判断
Gateway 断言工厂官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
服务路由 uri 使用 lb 开头即启用负载均衡,负载均衡策略可以通过 Ribbon来配置
service-name.ribbon.NFLoadBalancerRuleClassName 配置负载均衡策略,其中 service-name 为 uri 中的服务名称
默认策略为轮询访问
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service # lb 表示负载均衡,后跟服务名称
predicates:
- Path=/user/**
# 通过 Ribbon 配置某一服务的负载均衡策略
user-service: # 服务名称
ribbon:
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 随机访问策略
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # Nacos优先选择策略
路由过滤器是在路由中配置的过滤器,只会对当前路由生效
在路由配置中添加 filters 属性即可
示例如下:
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/user/**
filters: # 添加路由过滤器
- AddRequestHeader=from, gateway # 添加请求头 from=gateway
如上例使用了 - AddRequestHeader 用来给请求添加请求头
类似的常用的还有:
更多查看 GatewayFilter Factories 官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
default 过滤器对所有路由生效
配置 spring.cloud.gateway.default-filters
示例如下:
spring:
cloud:
gateway:
default-filters:
- AddRequestParameter=message, Hello # 添加请求参数 message=Hello
新建一个类实现 GlobalFilter 接口中的 filter 方法
并在类上注解 @Component 将类添加到 Spring 容器即可
filter 方法中的 exchange 参数表示上下文,其中可以获取 request, response, session 等信息
chain 参数表示过滤器链,可以进行放行操作
如下示例实现了简单的权限校验,检验请求头中是否携带了代表有权限的属性:
@Component
public class AuthorizeFilter implements GlobalFilter {
private static String adminAuth = "adminAuth";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取请求头中的 Authorization 属性值
HttpHeaders headers = exchange.getRequest().getHeaders();
String authorization = headers.getFirst("Authorization");
if (!adminAuth.equals(authorization)) {
// 设置 401 响应状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 完成响应,不再往后进行
return exchange.getResponse().setComplete();
}
// 放行
return chain.filter(exchange);
}
}
在全局过滤器上注解 @Order 注解可以设置过滤器的优先级,用于排列多个过滤器时的顺序
也可以实现 Ordered 接口中的 getOrder() 方法实现同样的效果
//@Order(1) // 注解设置 order 为 1
@Component
public class MyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange);
}
@Override
public int getOrder() { // 实现方法设置 order 为 1
return 1;
}
}
每一个过滤器都有一个 int 类型 order 值
过滤器的执行顺序按照 order 值进行排序的,order 值越小优先级越高,越先执行
全局过滤器的 order 由自己指定,路由过滤器与 defaultFilter 的 order 根据声明顺序由 1 开始递增
路由过滤器与 defaultFilter 的 order 值是独立分开的
当三种过滤器的 order 值相同时,有优先级:路由过滤器 > defaultFilter > 全局过滤器
yaml 配置示例如下:
spring:
cloud:
gateway:
globalcors: # 全局跨域处理
add-to-simple-url-handler-mapping: true # 解决 options 请求被拦截问题
cors-configurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8080"
allowedMethods: # 允许的跨域请求方法
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许跨域请求中携带的请求头:全部
allowCredentials: true # 是否允许携带 cookie
maxAge: 360000 # 跨域检测的有效期