1 是什么
API网关:在微服务之前增加一个前置节点,这个节点就是网关。网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
1.1 网关的作用
性能:API高可用,负载均衡,容错机制。
安全:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
日志:日志记录(spainid,traceid)一旦涉及分布式,全链路跟踪必不可少。
缓存:数据缓存。
监控:记录请求响应数据,api耗时分析,性能监控。
限流:流量控制,错峰流控,可以定义多种限流规则。
灰度:线上灰度部署,可以减小风险。
路由:动态路由规则。
2 怎么用
2.1 怎么用
最重要的几个概念:
Route(路由):它是网关的基础元素,包含ID、目标URI、断言、过滤器组成,当前请求到达网关时,会通过Gateway Handler Mapping,基于断言进行路由匹配,当断言为true时,匹配到路由进行转发。
Predicate(断言) :我们可以使用它来匹配来自HTTP中的任何请求,例如Headers或参数,一旦匹配为true,则表示匹配到合适的路由进行转发。
Filter(过滤器): 可以在请求发出的前后进行一些业务上的处理,比如授权、埋点、限流等。
- 创建gateway工程,添加gateway依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
- 配置文件中添加路由规则
server:
port: 8083
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes: #路由
- predicates: #断言
- Path=/gateway/**
filters:
- StripPrefix=1 #转发时跳过Path中的前缀gateway
uri: http://localhost:8082/ #拦截之后转发到哪个地址
- 启动项目
输入http://localhost:8083/gateway/config
如果想配置多个路由:
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes:
- id: config_route
predicates:
- Path=/gateway/**
filters:
- StripPrefix=1
uri: http://localhost:8082/
- id: cookie_route
predicates:
- Cookie=name,xiaohou
filters:
- StripPrefix=1
uri: http://localhost:8082/
3自定义断言
例如判断请求头中是否包含Authorization值为yuanxiaohou的数据,如果包含进行拦截
创建java类 必须以RoutePredicateFactory结尾,如AuthRoutePredicateFactory.java 继承AbstractRoutePredicateFactory
重写构造器,apply方法
@Component
public class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory<AuthRoutePredicateFactory.Config>{
private static final String NAME_KEY="name";
private static final String VALUE_KEY="value";
public AuthRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY,VALUE_KEY);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return serverWebExchange -> {
HttpHeaders headers = serverWebExchange.getRequest().getHeaders();
List<String> headerList = headers.get(config.getName());
return headerList.size()>0;
};
}
public static class Config{
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
application.yml中设置Auth ,注意Auth是自定义断言AuthRoutePredicateFactory类名的前缀部分,必须保持一致
使用postman工具请求头中携带Authorization=yuanxiaohou
返回报文中路由到百度首页,说明自定义断言生效。
4 自定义filter
和自定义断言类似,创建java类,类名以GatewayFilterFactory结尾,继承AbstractGatewayFilterFactory类,重写构造器,apply方法。
@Component
public class DefineGatewayFilterFactory extends AbstractGatewayFilterFactory<DefineGatewayFilterFactory.Config> {
private static final String NAME_KEY="name";
Logger logger= LoggerFactory.getLogger(DefineGatewayFilterFactory.class);
public DefineGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}
@Override
public GatewayFilter apply(Config config) {
return ((exchange,chain)->{
logger.info("[pre] Filter Request, name:"+config.getName());
//TODO 请求前做的操作
return chain.filter(exchange).then(Mono.fromRunnable(()->{
//TODO 返回前做的操作
logger.info("[post]: Response Filter");
}));
});
}
public static class Config{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
在application.yml中增加拦截器,其中Define是类名的前缀,根据自己的类名来写。
在浏览器中输入http://localhost:8083/config 进行验证
5 通过Eureka进行转发
- gateway工程添加eureka-client依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 添加Eureka服务注册中心
server:
port: 8083
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes:
- id: lb_routes
predicates:
- Path=/lb/**
filters:
- StripPrefix=1
uri: lb://spring-cloud-order-service/ #填写在Eureaka上的服务名
discovery:
locator:
enabled: true
lower-case-service-id: true
eureka:
client:
service-url:
defaultZone: http://localhost:9090/eureka
官网上关于filter还有很多例子,例如限流RequestRateLimiter,具体请参考
gateway官网学习地址
5 动态路由
有些项目路由规则需要动态增加或删除,这事需要增加acuator依赖
- gateway工程添加actuator依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- application.yml中打开端点
management:
endpoints:
web:
exposure:
include: "*"
-
输入地址:http://localhost:8083/actuator/gateway/routes,(IP和端口根据自己的实际项目来写,后面路径是固定的)可查看配置的路由规则
-
使用postman工具动态添加或删除路由
http://localhost:8083/actuator/gateway/routes/baidu_route
4.1 增加路由,选择post请求,创建请求报文,如请求http://localhost:8083/first时跳转到百度首页。
请求报文如下:
{
"id": "baidu_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [{
"args":{
"_genkey_0":1
},
"name":"StripPrefix"
}],
"uri": "https://www.baidu.com",
"order": 0
}
同样post请求发送刷新报文 http://localhost:8083/actuator/gateway/refresh
再次在浏览器输入地址 http://localhost:8083/actuator/gateway/routes可看到新增加的路由:
发送配置的地址:http://localhost:8083/first。跳转到百度首页说明增加路由成功:
4.2 删除路由:发送DELETE请求 http://localhost:8083/actuator/gateway/routes/baidu_route
注意:此种方法添加的路由只是存到了内存中,如果重启项目,新添加的路由不存在,如果需要持久化可以存到数据库中,这种方法先不介绍了,下次再研究。