概念
服务网关可以理解为医院的分诊台,控制请求可不可以进来,进到哪里,之前是使用zuul网关,但是zuul2一直跳票所以spring官方基于webFlux框架开发了geteway,相比zuul1稳定性更好,支持异步非阻塞 ,可以实现反向代理,熔断,监控等功能
核心
路由
网关的基本组成模块,由ID、目标url,一系列断言和过滤器组成,断言为trur则进行路由匹配
断言Predicate
可以匹配http请求中的所有内容,如果请求与断言相匹配则进行路由
过滤
spring框架中getewayFilter的实例,使用过滤器,可以在请求被路由前或者之后进行请求修改
工作流程
1.客户端向spring geteway 发起请求,在getewat handler mapping中找到路由映射,
2.发送到geteway web handler中,断言是否可以通过,通过则发送请求
3.在通过一系列过滤在请求之前(per)或请求之后(post),发送请求到微服务中,处理完返回
4.返回数据经过一系列过滤到web handler中
其核心逻辑就是过滤链和路由转发
入门使用
- yml网关配置
server: port: 9527 eureka: client: service-url: defaultZone: http://localhost:7001/eureka spring: application: name: cloud-geteway cloud: gateway: routes: - id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/payment/getPaymentById/** # 断言,路径相匹配的进行路由 - id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/payment/lb/** # 断言,路径相匹配的进行路由 - id: baudu_rout uri: https://www.kancloud.cn predicates: # - Path=/manual/thinkphp5_1 - Path=/manual/thinkphp5_1/353946 logging: level: root: debug
2.测试
代码配置 注入RouteLocator的Bean
@Configuration public class GateWayConfig { /** * 配置了一个id为route-name的路由规则, * 当访问地址 http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei * @param builder * @return */ @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { RouteLocatorBuilder.Builder routes = builder.routes(); routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build(); return routes.build(); } @Bean public RouteLocator customRouteLocator2(RouteLocatorBuilder builder) { RouteLocatorBuilder.Builder routes = builder.routes(); routes.route("path_route_atguigu2", r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build(); return routes.build(); } }
通过微服务名实现动态路由
开启注册中心动态创建路由,利用微服务名进行路由
spring: application: name: cloud-geteway cloud: gateway: discovery: locator: enabled: true #// 开启注册中心动态创建路由,利用微服务名进行路由
修改路由配置
routes: - id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 # uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://CLOUD-PAYMENT-SERVICE #匹配后提供服务的路由地址 predicates: - Path=/payment/getPaymentById/** # 断言,路径相匹配的进行路由 - After=2021-07-12T12:52:18.246+08:00[Asia/Shanghai] # 断言,路径相匹配的进行路由
断言(Predicate)的使用
启动geteway可以看到控制台输出
可以看到都在路由工厂内需要走的过程,断言配置都在这里面
常用的断言配置
- id: hystrix-rout uri: lb://CLOUD-ORDER-FEIGN-HYSTRIX-SERVER predicates: - Path= /consumer/payment/hystrix/ok/** - After=2021-07-12T12:52:18.246+08:00[Asia/Shanghai] #请求所需携带的cookie - Cookie=name,xxyy #请求头要有X-Request-Id属性并且值为整数的正则表达式 - Header=X-Request-Id,\d+ - Host=**.atguigu.com,xxx.baicu.com - Method=GET - #要有参数名username并且值还要是整数才能路由 - Query=username, \d+
说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。
自定义(过滤器)Filter
geteway有自己的filter,但是网关是在最外层做拦截的,进去之后就有微服务来做其他操作,所以更多的是使用自定义过滤器
geteway filter配置
spring: application: name: cloud-geteway cloud: gateway: discovery: locator: enabled: true #// 开启注册中心动态创建路由,利用微服务名进行路由 routes: - id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 # uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://CLOUD-PAYMENT-SERVICE #匹配后提供服务的路由地址 predicates: - Path=/payment/getPaymentById/** # 断言,路径相匹配的进行路由 - After=2021-07-12T12:52:18.246+08:00[Asia/Shanghai] # 断言,路径相匹配的进行路由 - id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 # uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://CLOUD-PAYMENT-SERVICE #匹配后提供服务的路由地址 predicates: - Path=/payment/lb/** # 断言,路径相匹配的进行路由 - After=2021-07-12T12:52:18.246+08:00[Asia/Shanghai] filters: #过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024 - AddRequestParameter=X-Request-Id,1024
自定义filter配置
@Component @Slf4j public class MyLogGetewayFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("测试================come in MyLogGetewayFilter=========================================="); //获取参数a是否存在 String a = exchange.getRequest().getQueryParams().getFirst("a"); System.out.println(a); if (null == a){ System.out.println("错误参数"); //返回错误码 exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); exchange.getResponse().setComplete(); } //放行 return chain.filter(exchange); } @Override public int getOrder() { //配置优先级 越小优先级越高 return 0; } }