微服务网关GateWay
基本功能:
安全,监控/埋点,限流等
2.1路由配置
2.1.1搭建环境
1. 创建工程导入坐标
<!--
springcloudgateway的内部是通过netty+webflux实现
webflux实现和springmvc存在冲突
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2. 配置启动类
@SpringBootApplication
public class ApiGateWayServerApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGateWayServerApplication.class,args);
}
}
3. 配置yml文件
server:
port: 8080
spring:
application:
name: api_gateway_server
cloud:
gateway:
routes:
#配置路由 路由id,路由到微服务的uri,断言(判断条件)
- id: product-service
uri: http://127.0.0.1:9001
predicates:
- Path=/product/**
2.1.2路由规则
2.1.3动态路由(面向服务的路由)
server:
port: 8080
spring:
application:
name: api_gateway_server
cloud:
gateway:
routes:
#配置路由 路由id,路由到微服务的uri,断言(判断条件)
- id: product-service
# uri: http://127.0.0.1:9001
uri: lb://service-product # lb://根据微服务名称从注册中心拉取服务请求路径
predicates:
- Path=/product/** #路由条件 path:路由匹配条件
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用IP地址注册
2.1.4路径重写
cloud:
gateway:
routes:
#配置路由 路由id,路由到微服务的uri,断言(判断条件)
- id: product-service
# uri: http://127.0.0.1:9001
uri: lb://service-product # lb://根据微服务名称从注册中心拉取服务请求路径
predicates:
# - Path=/product/** #路由条件 path:路由匹配条件
- Path=/product-service/** #讲当前请求转发到 http://127.0.0.1:9001/product/1
filters: #配置路由过滤器
- RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\
#配置自动的根据微服务名称进行路由转发 #http://localhost:8080/service-product/product/1
2.1.5开启微服务名称转发
#配置自动的根据微服务名称进行路由转发 #http://localhost:8080/service-product/product/1
discovery:
locator:
enabled: true #开启根据服务名称自动转发
lower-case-service-id: true #微服务名称以小写形式呈现
2.2过滤器
server:
port: 8080
spring:
application:
name: api_gateway_server
cloud:
gateway:
routes:
#配置路由 路由id,路由到微服务的uri,断言(判断条件)
- id: product-service
# uri: http://127.0.0.1:9001
uri: lb://service-product # lb://根据微服务名称从注册中心拉取服务请求路径
predicates:
# - Path=/product/** #路由条件 path:路由匹配条件
- Path=/product-service/** #讲当前请求转发到 http://127.0.0.1:9001/product/1
filters: #配置路由过滤器
- RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用IP地址注册
全局过滤器代码:
package com.yxkj.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @USER:
* @DATE: 2021-07-12
* @description:功能描述 自定义全局过滤器
* 实现 globalfilter,ordered接口
*/
@Component
public class LoginUserFilter implements GlobalFilter, Ordered {
/**
* 执行过滤器的业务逻辑
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("执行了自定义的全局过滤器");
return chain.filter(exchange); //继续向下执行
}
/**
* 指定过滤器的执行顺序,返回值越小,执行优先级越高
* @return
*/
@Override
public int getOrder() {
return 1;
}
}
2.3统一鉴权
2.4网关限流
2.4.1基于filter限流
(1)准备工作
redis
在工程中引入redis相应的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
(2)修改网关中的application.yml配置
server:
port: 8080
spring:
application:
name: api_gateway_server
redis:
host: localhost
pool: 6379
database: 0
cloud:
gateway:
routes:
- id: service-product
uri: lb://service-product
predicates:
- Path=/product-service/**
filters:
- name: RequestRateLimiter #使用限流过滤器,是springcloud getway提供的
args:
#使用SpEl从容器中获取对象
key-resolver: '#{@pathKeyResolver}'
#令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 1 #向令牌桶中填充的速率
#令牌桶的上限
redis-rate-limiter.burstCapacity: 3 #令牌桶的容量
- RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用IP地址注册
(3)配置redis中key的解析器KeySesover
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @USER:
* @DATE: 2021-07-12
* @description:功能描述
*/
@Configuration
public class KeyResolverConfiguration {
/**
* 编写基于请求路径的限流规则
* //abc
* //基于请求ip 127.0.0.1
* //基于参数
*/
// @Bean
// public KeyResolver pathKeyResolver(){
// //自定义的keyResolver
// return new KeyResolver() {
// /**
// * ServerWebExchange 上下文参数
// *
// *
// * @param exchange
// * @return
// */
// @Override
// public Mono<String> resolve(ServerWebExchange exchange) {
// return Mono.just( exchange.getRequest().getPath().toString());
// }
// };
// }
/**
* 基于请求参数的限流
* 请求 abc? userId=1
* @return
*/
@Bean
public KeyResolver userKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
}
2.4.2基于sentinel限流
Sentinel支持对Spring cloud Gateway、Zuul等主流的API Gateway进行限流
application.yml配置
server:
port: 8080
spring:
application:
name: api_gateway_server
redis:
host: localhost
pool: 6379
database: 0
cloud:
gateway:
routes:
- id: service-product
uri: lb://service-product
predicates:
- Path=/product-service/**
filters:
# - name: RequestRateLimiter #使用限流过滤器,是springcloud getway提供的
# args:
# #使用SpEl从容器中获取对象
# key-resolver: '#{@userKeyResolver}'
# #令牌桶每秒填充平均速率
# redis-rate-limiter.replenishRate: 1 #向令牌桶中填充的速率
# #令牌桶的上限
# redis-rate-limiter.burstCapacity: 3 #令牌桶的容量
- RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\
#配置Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用IP地址注册
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
/**
* 配置限流的异常处理器,SentinelGatewayBlockExceptionHandler
* @return
*/
@Bean
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){
return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
}
/**
* 配置限流过滤器
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter(){
return new SentinelGatewayFilter();
}
/**
* 配置初始化的限流参数
* 用于指定资源的限流规则
* 1.资源名称(路由id)
* 2.配置统计时间
* 3.配置限流阈值
*/
@PostConstruct
public void initGatewayRules(){
Set<GatewayFlowRule> rules = new HashSet<>();
// rules.add(new GatewayFlowRule("service-product").setCount(1).setIntervalSec(1));
// rules.add(new GatewayFlowRule("order-api").setCount(1).setIntervalSec(1));
rules.add(new GatewayFlowRule("product-api").setCount(1).setIntervalSec(1));
GatewayRuleManager.loadRules(rules);
}
/**
* 自定义限流处理器
*/
@PostConstruct
public void initBlockHandlers(){
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Map<String,Object> map = new HashMap<>();
map.put("code","101");
map.put("message","限流啦!!!!稍等一会");
return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
/**
* 自定义API限流分组
* 1.定义分组
* 2.对小组配置限流规则
*/
@PostConstruct
private void initCustomizedApis(){
Set<ApiDefinition> definitions = new HashSet<>();
ApiDefinition api1 = new ApiDefinition("product-api")
.setPredicateItems(new HashSet<ApiPredicateItem>(){{
add(new ApiPathPredicateItem().setPattern("/product-service/product/**").
setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});
definitions.add(api1);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
}
2.5网关的高可用