spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: gate_hi
uri: lb://gateway-hi
predicates:
- Path=/retry/*
filters:
- StripPrefix=1
- name: Retry
args:
retries: 3
series: SERVER_ERROR
methods: GET,POST
retries:重试次数
series: SERVER_ERROR,下游服务报5XX系列的错误触发重试机制
methods:重试的HTTP方法
hi服务hello接口
@GetMapping("hello")
public String hello(@RequestParam String name) {
int i = 1 / 0;
return "hi," + name + " ! " + "访问端口号:" + port;
}
添加 hystrix 依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
熔断配置
server:
port: 8026
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
spring:
application:
name: gateway-limit
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: gateway_hi
uri: lb://gateway-hi
predicates:
- Path=/hi/*
filters:
- StripPrefix=1
#熔断
- name: Hystrix
args:
name: localfallback
fallbackUri: forward:/fallback
回调方法在网关服务
@RestController
public class IndexController {
@RequestMapping("/fallback")
public String fallback() {
System.out.println("fallback");
return "local fallback";
}
}
启动服务 eureka、hi、gateway-limit
正常访问:
http://localhost:8026/hi/hello?name=yzm
修改:
将回调方法部署到ha服务上
@RequestMapping("/fallback")
public String fallback() {
System.out.println("fallback");
return "ha fallback";
}
注释gateway服务上的fallback()方法
@RestController
public class IndexController {
// @RequestMapping("/fallback")
public String fallback() {
System.out.println("fallback");
return "local fallback";
}
}
spring:
application:
name: gateway-limit
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: gateway_hi
uri: lb://gateway-hi
predicates:
- Path=/hi/*
filters:
- StripPrefix=1
#熔断
- name: Hystrix
args:
name: remotefallback
fallbackUri: forward:/fallback
- id: gateway_ha
uri: lb://gateway-ha
predicates:
- Path=/fallback
启动服务 eureka、ha、gateway-limit,不用启动hi
访问 http://localhost:8026/hi/hello?name=yzm
添加依赖 redis-reactive
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
限流配置
spring:
application:
name: gateway-limit
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: gateway_hi
uri: lb://gateway-hi
predicates:
- Path=/hi/limit/*
filters:
- StripPrefix=2
#限流
- name: RequestRateLimiter
args:
key-resolver: '#{@remoteAddrKeyResolver}'
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 3 #令牌桶容量
# redis连接配置
redis:
host: 192.168.8.128
port: 6379
password: 1234
database: 0
key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
键解析器
/**
* 用于限流的键的解析器的 Bean 对象名字。
* 它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。
* 默认情况下,使用PrincipalNameKeyResolver,以请求认证的java.security.Principal作为限流键。
*/
@Component
public class RemoteAddrKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
// 根据IP地址限流
String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
System.out.println("hostAddress = " + hostAddress);
// 根据请求地址限流
String uriPath = exchange.getRequest().getURI().getPath();
System.out.println("uriPath = " + uriPath);
// 根据用户ID
//String userId = exchange.getRequest().getQueryParams().getFirst("userId");
return Mono.just(hostAddress);
}
}
引入依赖
<!-- 令牌桶 -->
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>4.0.0</version>
</dependency>
定义过滤器
/**
* 根据IP Address限流
*/
@Data
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class RateLimitByIpGatewayFilter implements GatewayFilter, Ordered {
//桶的最大容量,即能装载 Token 的最大数量
int capacity;
//每次 Token 补充量
int refillTokens;
//补充 Token 的时间间隔
Duration refillDuration;
private static final Map<String, Bucket> CACHE = new ConcurrentHashMap<>();
private Bucket createNewBucket() {
Refill refill = Refill.of(refillTokens, refillDuration);
Bandwidth limit = Bandwidth.classic(capacity, refill);
return Bucket4j.builder().addLimit(limit).build();
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
Bucket bucket = CACHE.computeIfAbsent(ip, b -> createNewBucket());
log.info("IP: " + ip + ",TokenBucket Available Tokens: " + bucket.getAvailableTokens());
if (bucket.tryConsume(1)) {
return chain.filter(exchange);
} else {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder() {
return -1000;
}
}
配置路由
package com.yzm.gatewaylimit.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;
import java.time.Duration;
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 根据令牌限流
.route(p -> p
.path("/ip/**")
.filters(f -> f
.stripPrefix(1)
.filter(new RateLimitByIpGatewayFilter(3,1, Duration.ofSeconds(1))))
.uri("http://httpbin.org:80"))
.build();
}
}
桶最大容量3个,每秒产出1个token
首页
上一篇:Gateway过滤器