Gateway
目前,我们的微服务架构已经有了微服务集群、注册中心和配置中心,并且我们的微服务集群可以利用各种远程调用协议来相互调用。
不过,在当前的场景下,用户如果想要去使用某个服务,他必须直接调用微服务,这对用户十分不友好,用户可能要记住很多很多服务的IP及端口,并且,他要手动选择到一个具体的服务实例上,这让我们无法对用户想要访问的请求做一个负载均衡,并且,一些服务可能是需要对外部隐藏的,只在微服务内部被调用,也有一些可能需要权限的校验。总结一下就是:
- 杂乱的微服务实例,对用户不友好
- 缺少负载均衡机制
- 暴露所有微服务,应该根据实际情况隐藏或校验访问权限
总的来说,问题很多,但都可以归结为:我们的系统缺少一个面向用户的门面
而这个门面,就可以用网关来实现,SpringCloud中提供了两个网关组件:Gateway
和Zuul
,这节主要介绍Gateway
。
所以,网关的目的就是给用户提供一个一致的接口,并可以在其中做任何操作,比如负载均衡、隐藏服务、权限校验
QuickStart#
创建网关项目#
网关是微服务架构中的一个单独组件,就像一个单独的服务实例,所以我们要创建一个项目网关项目。
然后,引入如下依赖:
<dependencies>
<!-- 网关组件依赖 -->
<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>
</dependencies>
为什么网关需要引入nacos?因为它要转发用户的请求到实际的微服务实例,所以它要获取所有的服务列表,并且在其中做负载均衡。
配置application.yaml#
下面的配置较长,但除了gateway
中的内容,剩下的我们都见过:
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/user/**
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/order/**
server:
port: 80
简单的说一下,上面的配置就是配置了一下nacos注册中心的地址用于网关拉取微服务实例信息,并且将自己的端口设置为80,服务名设置成gateway。
然后,在spring.cloud.gateway.routes
中配置了路由规则。
路由规则#
既然网关要将用户发给它的请求路由到微服务实例上,那么怎么路由?这就是路由规则指定的。
routes
是一个list,list中的元素又是一个map,每一个元素描述一个路由规则。
id
描述了路由规则的唯一标识uri
描述要将请求映射到哪里,这里的lb
协议代表启用负载均衡,然后后面跟的是服务名,你也可以跟http://ip
predicates
描述了路由映射的断言列表,如果用户请求满足断言列表中的所有断言时,它就会被路由到uri
上
所以上面,我们提供了一个到user-service
的路由,当请求路径中带有/user
前缀就匹配到这个路由,同理还有一个order-service
的路由。
运行#
总结#
现在我们通过Gateway组件解决了之前的问题:
- 用户对系统的访问仅仅通过网关
- 网关可以提供相同服务间的负载均衡机制
- 你可以通过路由规则对用户隐藏某些服务
断言工厂#
gateway
提供了一个接口:RoutePredicateFactory
,它是生成一种路由断言规则的东西,它有如下实现类:
这些实现类都是我们可以使用的断言方式,其中,有我们已经使用过的也是最常用的,基于路径的PathRoutePredicateFactory
。
下面是可以使用的断言列表:
过滤器工厂#
过滤器允许你对转发到微服务实例的请求以及从微服务实例拿到的响应做一些处理,有如下的过滤器:
其中可以看到,有对请求头做处理的,有对响应头做处理的,有做断路器的等等,其实这个列表中总共有32个Filter。
你可以通过配置文件来对某个路由规则添加filter,也可以添加默认filter,即作用于所有路由规则的filter:
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/user/**
filters:
- AddResponseHeader=CustomHeader, CustomValue
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/order/**
default-filters:
- AddResponseHeader=DefaultCustomHeader, DefaultCustomValue
上面的代码中,我们给user-service-route
这个路由规则添加了一个添加响应头的Filter,并添加了我们自定义的响应头,同时通过default-filters
给所有路由规则添加默认的过滤器。
再次访问user服务,携带了两个自定义的响应头:
而访问order服务,只携带了一个默认自定义响应头:
全局过滤器#
有时候我们需要实现一些逻辑和业务相关性比较高的过滤器,此时不能指望上面的那些过滤器了,我们可以自己实现GlobalFilter
接口来定义自己的过滤逻辑。
@Order(-1) // 设置过滤器顺序
@Component // 将过滤器声明为一个Bean
public class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 检查参数中的`role`,判断是否为`admin`,如果是,放行,否则终结这个请求
if (params.containsKey("role") && params.getFirst("role").equals("admin")) {
return chain.filter(exchange);
}
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
}
过滤器顺序#
Gateway会将到来的请求匹配的所有过滤器合并,其中包括当前路由的过滤器、默认过滤器和全局过滤器,并将合并后的过滤器集合排序。
- 每一个过滤器都有一个order序号,序号越小优先级越高
- GlobalFilter的序号是通过
@Order
定义的 - 路由过滤器和default过滤器的顺序按照定义顺序从1递增,并且它们分开计数,即一个路由过滤器中的第一个order是1,但不影响default中第一个也是1
- 当两个过滤器序号相同时(只可能在不层次的过滤器上发生,比如不可能在两个默认过滤器上发生),顺序是defaultFilter > 路由过滤器 > GlobalFilter
跨域处理#
如果我们的网关有可能被浏览器通过ajax
跨域访问的话,那可以做一些跨域相关的配置:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true # 解决默认Options请求被拦截的问题
cors-configurations:
'[/**]':
allowed-origins:
- "http://localhost:8090"
allowed-methods:
- "GET"
- "POST"
- "PUT"
- "DELETE"
- "OPTIONS"
allowed-headers: "*"
allow-credentials: true # 允许携带cookie
max-age: 360000 # 跨域有效期
作者:Yudoge
出处:https://www.cnblogs.com/lilpig/p/16557121.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
欢迎按协议规定转载,方便的话,发个站内信给我嗷~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)