之前我一直用的是Zuul网关,用过gateway以后感觉比Zuul功能还是强大很多。
Spring Cloud Gateway是基于Spring5.0,Spring Boot2.0和Project Reactor等技术开发的,用来为微服务架构提供一种简单有效统一的API路由管理方式。
相比Zuul,GateWay不仅仅提供统一的路由方式,还提供了例如:安全,限流,监控/指标,重试机制,熔断回调,过滤等功能,这些都是可配置的。
原理什么的就不多说了,可以看下官方文档
首先添加Maven依赖
<!-- gateway --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 熔断器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!-- 限流 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> <!-- eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--暴露各种指标--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- zipkin-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
yml配置详情如下:
#连接Eureka配置 eureka: client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/ server: port: 8770 spring: main: banner-mode: application: name: dkjk-gateway-service #应用程序名 # redis: # host: localhost # port: 6379 cloud: gateway: routes: - id: my-service-one #我们自定义的路由 ID,保持唯一 #目标服务地址,也可以是http://localhost:8182 PS: 当所用协议为lb时, #gateway将使用 LoadBalancerClient把服务名通过eureka解析为实际的主机和端口,并进行负载均衡。 uri: lb://Eureka中的服务名称1 # order: 0 #路由规则,Predicate 接受一个输入参数,返回一个布尔值结果。
#该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。 predicates: # PS:以下规则可以组合使用 #接收一个匹配路径的参数来判断是否走路由。当访问地址 http://localhost:8770/spring-cloud时
#会自动转发到地址:http://www.ityouknow.com/spring-cloud - Path=/em/** #可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由。可以用postman测试,如果符合规则进行路由,否则不进行路由(报404) # - Method=GET #请求时间在 2019年11月04日6点6分6秒之前可以进行路由,在这时间之后停止路由(报404) # - Before=2019-11-04T06:06:06+08:00[Asia/Shanghai] #请求时间在 2019年11月04日16点31分00秒之前不可以进行路由(报404),在这时间之后可以进行路由 # - After=2019-11-05T16:31:00+08:00[Asia/Shanghai] #在这个时间段内可以匹配到此路由,超过这个时间段范围则不会进行匹配(报404)。可以用在限时抢购的一些场景中。 # - Between=2019-11-04T06:06:06+08:00[Asia/Shanghai], 2019-11-06T06:06:06+08:00[Asia/Shanghai] #两个参数:1.请求头中属性名称2.正则表达式(也可以是固定值),可以用postman测试,如果符合规则进行路由,否则不进行路由(报404) # - Header=apikey, d+ #两个参数:1.Cookie name 值2.正则表达式(也可以是固定值),可以用postman测试,如果符合规则进行路由,否则不进行路由(报404) # - Cookie=apikey, d+ #只要请求中包含apikey属性的参数即可匹配路由。如果符合规则进行路由,否则不进行路由(报404) # - Query=apikey # - Host=**.ityouknow.com #通过设置某个 ip 区间号段的请求才会路由,即符合这个网段的可以访问,例如:http://192.168.1.131:8770/ # - RemoteAddr=192.168.1.1/24 # 过滤规则 filters: #截取路径的个数 - StripPrefix=1 #在URL路径前面添加一部分的前缀,例如:配置 - Path=/** , 请求路径为localhost:8770/idcard,
#会转变为localhost:8770/identity/idcard # - PrefixPath=/identity - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback #如果服务调用异常会回调自定义的/fallback请求 - id: credit-service uri: lb://Eureka中的服务名称2 predicates: - Path=/credit/** filters: - StripPrefix=1 - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback #如果服务调用异常会回调自定义的/fallback请求 - name: RequestRateLimiter #名称必须是 RequestRateLimiter args: redis-rate-limiter.replenishRate: 2 #允许用户每秒处理多少个请求 redis-rate-limiter.burstCapacity: 3 #令牌桶的容量,允许在一秒钟内完成的最大请求数 key-resolver: "#{@userKeyResolver}" #使用 SpEL 按名称引用 bean - name: Retry args: #重试次数,默认值是3次 retries: 3 series: - SERVER_ERROR #满足的status statuses: - BAD_GATEWAY methods: - GET - POST exceptions: - java.io.IOException - java.util.concurrent.TimeoutException - java.lang.RuntimeException #是否与服务注册于发现组件进行结合,通过 serviceId 转发到具体的服务实例。
#默认为 false,设为 true 便开启通过服务中心的自动根据 serviceId 创建路由的功能。 #这个不用配置也可以 # discovery: # locator: # enabled: true # hystrix 信号量隔离,30秒后自动超时 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 30000 logging: level: org.springframework.cloud.gateway: debug
以上配置启动类中用到的注解
package com.dkjk.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class DkjkGatewayServiceApplication { public static void main(String[] args) { SpringApplication.run(DkjkGatewayServiceApplication.class, args); } }
限流配置代码
package com.dkjk.gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; /** * @Description: * @Author: qjc * @Date: 2019/11/6 */ @Configuration public class Config { @Bean KeyResolver userKeyResolver() { // return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));//根据请求参数中的 user 字段来限流 return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());//根据请求 IP 地址来限流 } }
熔断回调代码:
package com.dkjk.gateway.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @Description: * @Author: qjc * @Date: 2019/11/6 */ @RestController @Slf4j public class FallbackController { @GetMapping("/fallback") public String fallback() { log.info("回调了"); return "Hello World! from gateway"; } }