Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关
可是在2.x版本中,zuul的升级一直跳票,SpringCloud最后本身研发了一个网关代替Zuul
那就是Springcloud Gateway一句话: gateway是原zuul 1.x版的替代java
Springcloud Gateway使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通信框架react
neflix不太靠谱,zuul2.0一直跳票,迟迟不发布web
SpringCloud Finchley正式版以前,Spring Cloud 推荐的网关是Netflix提供的Zuul正则表达式
Zuul 1.x 是基于servlet之上的一个阻塞式处理模型,即spring实现了处理全部request请求的一个servlet 并由该servlet阻塞式处理处理,因此Springcloud Zuul没法摆脱serverlet模型的弊端spring
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,若是断言为true则匹配该路由apache
参考的是Java8的java.util.function.Predicate
开发人员能够匹配HTTP请求中的全部内容(例如请求头或请求参数),若是请求与断言相匹配则进行路由编程
指的是Spring框架中GatewayFilter的实例,使用过滤器,能够在请求被路由器前或者以后对请求进行修改。设计模式
Web请求,经过一系列匹配条件,定位到真正的服务节点。并在这个转发过程的先后,进行一些精细化的控制
predicate就是咱们的匹配条件
filter,能够理解为一个无所不能的拦截器。有了这两个元素在加上目标uri,就能够实现一个具体的路由了api
路由转发+执行过滤器链架构
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.aiguigu.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-gateway-gateway9527</artifactId> <dependencies> <!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--eureka client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--引入自定义的api通用包,可以使用Payment支付Entity--> <dependency> <groupId>com.aiguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> <!--通常基础配置类--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
server: port: 9527 spring: application: name: cloud-gateway cloud: gateway: routes: - id: payment_routh #payment_routh #路由的ID,没有固定规则但要求惟一,简易配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2 #payment_routh #路由的ID,没有固定规则但要求惟一,简易配合服务名 uri: http://localhost:8001 #匹配后提供服务的路由地址 predicates: - Path=/payment/lb/** #断言,路径相匹配的进行路由 eureka: instance: hostname: cloud-gateway-service client: fetch-registry: true register-with-eureka: true service-url: #设置与Eureka Server交互的地址查询服务和注册服务都须要依赖这个地址 # defaultZone: http://eureka7002.com:7002/eureka/ # 单机版eureka defaultZone: http://eureka7001.com:7001/eureka/
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class GatewayMain9527 { public static void main(String[] args) { SpringApplication.run(GatewayMain9527.class,args); } }
已经注册成功:
这里新建一个config
配置路由规则,代替yml配置
package com.atguigu.springcloud.config; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){ RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes(); routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build(); return routes.build(); } }
测试:
请求要知足断言表达式为true才能访问,只要一个不符合就访问不到服务
在当前时间以后才能访问
时间格式复杂怎么办?这里有生成当前时间的方法
import java.time.ZonedDateTime; public class TimeBulider { public static void main(String[] args) { ZonedDateTime zonedDateTime=ZonedDateTime.now(); System.out.println(zonedDateTime); } }
测试,若是我将时间调至明天,再次访问会出现找不到服务
能够看到这里断言还有After,Before和Between,方法都是大同小异
- Header=X-Request-Id, \d+ #请求头须要有X-Request-Id属性名,值为整数正则表达式
命令输入:http://localhost:9527/payment/lb -H “X-Request-Id:1234”,负数就直接报错
全部断言不一一举例了,说白了Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理
建立Gateway配置类
实现一个GlobalFilter
package com.atguigu.springcloud.filter; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.Date; @Component @Slf4j @Order(0) public class MyLogGateWayFilter implements GlobalFilter,Ordered{ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("***************Come in My LogGlobalFilter "+new Date()); String uname = exchange.getRequest().getQueryParams().getFirst("uname"); if(uname==null){ log.info("*******用户名非法,请稍后再试!"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } // @Override 实现上面@Order(0)注解就能够不用实现接口 public int getOrder() { return 0; } }
测试
注意:请求进来必须带有uname的参数才能够访问,测试以下