在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。这样的话会产生很多问题,例如:
Spring Cloud Gateway 基于Spring Boot 2.x、Spring WebFlux和Project Reactor,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。基于Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架
特点:
路由(Route) 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面的几个信息:
客户端向 Spring Cloud Gateway 发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler 处理程序。此处理程序通过特定于请求的Fliter链运行请求。Fliter被虚线分隔的原因是Fliter可以在发送代理请求之前(pre)和之后(post)运行逻辑。执行所有pre过滤器逻辑。然后进行代理请求。发出代理请求后,将运行“post”过滤器逻辑。
过滤器作用:
核心点
GateWay核心的流程就是:路由转发+执行过滤器链
版本对应地址:https://spring.io/projects/spring-cloud
因为gateway是Spring cloud的,我们需要在父工程引入spring cloud的依赖
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud-gateway-varsion}
pom
import
在我们的9999网关服务引入nacos和geteway依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-gateway
配置yaml文件
server:
port: 9999
spring:
application:
name: cloud-getway-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: nacos-payment-provider
uri: http://localhost:9001/nacos-payment-provider
predicates:
- Path=/test/**
启动Nacos服务,9999网关服务,9001服务,通过浏览器访问其他服务,效果如下:
我们可以通过代码来配置网关
新建配置类,交由Spring管理
@Configuration
public class TestGetWayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("nacos-payment-provider", r -> r.path("/test/**").uri("http://localhost:9001/nacos-payment-provider"))
.route("nacos-payment-provider2", r -> r.path("/**").uri("http://localhost:9002/nacos-payment-provider2"))
.build();
}
}
正常访问浏览器即可。
手动配置负载均衡
uri: lb
server:
port: 9999
spring:
application:
name: cloud-gateway-9999
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
enabled: true #开启自动路由功能(此时可以关闭)
routes: # 路由
- id: nacos-payment-provider #路由ID,没有固定要求,但是要保证唯一,建议配合服务名
uri: lb://nacos-payment-provider # 匹配提供服务的路由地址
predicates: # 断言
- Path=/test/**
参考Spring官网案例:
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
工作中最常用的就是自定义顾虑器
我们需要创建一个自定义过滤器类,实现Ordered, GlobalFilter
@Component
@Slf4j
public class MyFilter implements Ordered, GlobalFilter {
/**
* @param exchange 可以拿到对应的request和response
* @param chain 过滤器链
* @return 是否放行
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String username = exchange.getRequest().getQueryParams().getFirst("username");
log.info("*************MyFilter:"+new Date());
if(username == null){
log.info("**********用户名为null,非法用户,请求被拒绝!");
//如果username为空,返回状态码为406,不可接受的请求
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
/**
* 加载过滤器的顺序
* @return 整数数字越小优先级越高
*/
@Override
public int getOrder() {
return 0;
}
}
访问浏览器,如果我们的接口地址中没有携带username参数则拒绝访问,否则成功响应
如果对你有帮助,可以关注博主(不定期更新各种技术文档)
给博主一个免费的点赞以示鼓励,谢谢 ! 欢迎各位点赞评论收藏⭐️