SpringCloud(H版)学习---服务网关
一、概述
上一代zuul 1.x:https://github.com/Netflix/zuul/wiki
关于zuul的鄙人之前博客:SpringCloud全家桶学习之路由网关----Zuul(六),不过看上图就知道该用谁了,没错-----GateWay(其用到了一些新技术如Netty、Spring Web Flux等)更值得我们学习。
二、Gateway
官网地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
Spring Cloud Gateway基于Web Flux框架实现,而Web Flux框架底层则使用了高性能的Reactor模式通信框架Netty。SpringCloud Gateway的目标是提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如安全、监控/指标,限流等。
1、三大核心概念
(1)Route路由:路由是构建网关的基本模块,它由ID、目标URI、一系列的断言和过滤器组成,如果断言为true则匹配该路由
(2)Predicate断言:开发人员可以匹配Http请求中的所有内容(例如请求头、请求参数)如果请求与断言相匹配则进行路由(参考:Java8:java.util.function.Predicate)
(3)Filter过滤:指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由之前或者之后对请求进行修改
2、工作流程
①客户端向SpringCloud Gateway发出请求,然后在GateWay Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Hander;
②Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑
③Filter在“pre”类型的过滤器中可以做参数校验、权限校验、流量监控、日志输出、协议转换等;在“post”类型的过滤器中可以做响应内容、响应头的修改、日志输出、流量监控等有着非常重要的作用。
核心逻辑:路由转发+执行过滤器链
三、Gateway工程搭建
1、网关路由配置
1、yml配置网关路由
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称j进行路由 routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 uri: http://localhost:8001 predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 #- After=2017-01-20T17:42:47.789-07:00[America/Denver] #- Before=2017-01-20T17:42:47.789-07:00[America/Denver] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ #请求头要有X-Request-Id属性,并且值为正数 #- Host=**.atguigu.com #- Method=GET #- Query=username, \d+ # 要有参数名username并且值还要是正整数才能路由 # 过滤 #filters: # - AddRequestHeader=X-Request-red, blue - id: payment_route2 uri: http://localhost:8001 predicates: Path=/payment/lb/** #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
分析:
①添加网关前访问:http://localhost:8001/payment/get/31
②添加网关后访问:http://localhost:9527/payment/get/31
2、硬编码方式注入RouteLocator Bean配置路由
参考官网案例:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
业务需求:通过9527网关访问到外网的百度新闻网址
@Configuration public class GatewayConfig { /** * 配置了一个id为route-name的路由规则 * 当访问localhost:9527/guonei的时候,将会转发至https://news.baidu.com/guonei * * @param routeLocatorBuilder * @return */ @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) { RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); return routes.route("path_route_xd", r -> r.path("/guonei").uri("https://news.baidu.com/guonei")).build(); } @Bean public RouteLocator customRouteLocator2(RouteLocatorBuilder routeLocatorBuilder) { RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); return routes.route("path_route_xd1", r -> r.path("/guoji").uri("https://news.baidu.com/guoji")).build(); } }
分析:上述配置provider方提供均是写死的,需要改造。
3、微服务名实现动态路由配置
默认情况下,Gateway会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。将uri配置为微服务名,并负载均衡
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: discovery: locator: enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由 routes: - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名 #匹配后提供服务的路由地址 # uri: http://localhost:8001 uri: lb://CLOUD-PAYMENT-SERVICE predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 #- After=2017-01-20T17:42:47.789-07:00[America/Denver] #- Before=2017-01-20T17:42:47.789-07:00[America/Denver] #- Cookie=username,zzyy #- Header=X-Request-Id, \d+ #请求头要有X-Request-Id属性,并且值为正数 #- Host=**.atguigu.com #- Method=GET #- Query=username, \d+ # 要有参数名username并且值还要是正整数才能路由 # 过滤 #filters: # - AddRequestHeader=X-Request-red, blue - id: payment_route2 uri: lb://CLOUD-PAYMENT-SERVICE # uri: http://localhost:8001 predicates: Path=/payment/lb/** #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
2、常用Predicates
官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories,
可以对路由进行更精细的控制,例如header、cookie等等。
3、自定义Filter
Filter分类:Gateway Fliter(单一31种)、Global Filter(全局--10种)
自定义过滤器类实现GlobalFilter,Orderd接口即可
@Component @Slf4j public class MyLogGatewayFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("come in global filter: {}", new Date()); ServerHttpRequest request = exchange.getRequest(); String uname = request.getQueryParams().getFirst("uname"); if (uname == null) { log.info("用户名为null,非法用户"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } // 放行 return chain.filter(exchange); } /** * 过滤器加载的顺序 越小,优先级别越高 * * @return */ @Override public int getOrder() { return 0; } }