上一代zuul 1.x官网
Gateway官网
Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;
但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway—句话:gateway是原zuul1.x版的替代
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fuLsvolV-1653224498500)( https://com-qianyue-img.oss-cn-hangzhou.aliyuncs.com/img/54b61d819aa1630bc61732de340b55b4.png)]
Gateway是在Spring生态系统之上构建的API网关服务,由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中
工作,也不能构建成 war 包
1.2 Gateway可以干什么Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的 基本功能,例如说安全认证、监控、限流等等。
1.3 Gateway在微服务架构中的位置 1.4 Gateway核心组件三大核心概念
Route(路由) - 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由;
Predicate(断言) - 参考的是Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由;
Filter(过滤) - 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改(此过滤非SpringMVC的过滤器)。
1.客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关Web 处理程序,此时处理程序运行特定的请求过滤器链。
2.过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。
2.Gateway实战 2.1 环境搭建1.新建网关模块,添加依赖
org.springframework.cloud spring-cloud-starter-gateway com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.projectlombok lombok 1.18.10
2.yaml配置
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
enabled: true #是否开启网关
3.添加主启动类
@SpringBootApplication
public class MallGatewayApplication8888 {
public static void main(String[] args) {
SpringApplication.run(MallGatewayApplication8888.class,args);
}
}
2.2 实战操作
2.3.1 通过微服务名称调用
(1).配置
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true #为true代表 我们可以通过微服务名称调用,不推荐
enabled: true #是否开启网关
(2).测试 访问http://localhost:8888/mall-order/order/findOrderByUserId/1,这种方式太low了我们是不希望微服务名称暴漏的。
2.3.2 路由加断言Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个RoutePredicate工厂可以进行组合。Spring Cloud Gateway创建Route 对象时,使用RoutePredicateFactory 创建 Predicate对象,Predicate 对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and。
常用的Route Predicate Factory
The After Route Predicate Factory
The Before Route Predicate Factory
The Between Route Predicate Factory
The Cookie Route Predicate Factory
The Header Route Predicate Factory
The Host Route Predicate Factory
The Method Route Predicate Factory
The Path Route Predicate Factory
The Query Route Predicate Factory
The RemoteAddr Route Predicate Factory
The weight Route Predicate Factory
下边以其中几个常用的断言演示下效果
1.Path断言(1)配置
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true #为true代表 我们可以通过微服务名称调用,不推荐
enabled: true #是否开启网关
routes:
- id: order_route #路由ID,全局唯一
#uri: http://localhost:8020 #目标微服务的请求地址和端口 我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
uri: lb://mall-order
predicates:
- Path=/order
@Component
@Slf4j
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory {
public CheckAuthRoutePredicateFactory() {
super(Config.class);
}
@Override
public Predicate apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
log.info("调用CheckAuthRoutePredicateFactory" + config.getName());
if("auth".equals(config.getName())){
return true;
}
return false;
}
};
}
@Override
public List shortcutFieldOrder() {
return Collections.singletonList("name");
}
public static class Config {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
2.yaml配置
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true #为true代表 我们可以通过微服务名称调用,不推荐
enabled: true #是否开启网关
routes:
- id: order_route #路由ID,全局唯一
#uri: http://localhost:8020 #目标微服务的请求地址和端口 我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
uri: lb://mall-order
predicates:
- Path=/order
@RestController
@RequestMapping("/order")
@Slf4j
public class GatewayController {
@GetMapping("/testgateway")
public String testGateway(HttpServletRequest request) throws Exception {
log.info("gateWay获取请求头X-Request-color:"
+request.getHeader("X-Request-color"));
String color = request.getParameter("color");
log.info("gateWay获取请求参数color:"
+color);
return "success";
}
@GetMapping("/testgateway2")
public String testGateway(@RequestHeader("X-Request-color") String color) throws Exception {
log.info("gateWay获取请求头X-Request-color:"+color);
return "success";
}
@GetMapping("/testgateway3")
public String testGateway3(@RequestParam("color") String color) throws Exception {
log.info("gateWay获取请求参数color:"+color);
return "success";
}
}
(2)在gateway网关层添加配置
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true #为true代表 我们可以通过微服务名称调用,不推荐
enabled: true #是否开启网关
routes:
- id: order_route #路由ID,全局唯一
#uri: http://localhost:8020 #目标微服务的请求地址和端口 我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
uri: lb://mall-order
predicates:
- Path=/order
@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
log.info("调用CheckAuthGatewayFilterFactory==="
+ config.getName() + ":" + config.getValue());
// TODO
return chain.filter(exchange);
};
}
}
(2)yaml配置
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true #为true代表 我们可以通过微服务名称调用,不推荐
enabled: true #是否开启网关
routes:
- id: order_route #路由ID,全局唯一
#uri: http://localhost:8020 #目标微服务的请求地址和端口 我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
uri: lb://mall-order
predicates:
- Path=/order
@Configuration
public class GatewayConfiguration {
private final List viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
4.配置流控规则 访问http://127.0.0.1:8888/order/findOrderByUserId/1 在sentinel控制台配置流控规则 可以看出此时的资源名称就是我们的route-id
5.测试 快速访问访问http://127.0.0.1:8888/order/findOrderByUserId/1 说明我们流控成功。
2.3.5.2 手动配置流控规则(1)编写配置类
@Configuration
public class GatewayConfiguration {
private final List viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit() {
// //初始化自定义的API
initCustomizedApis();
// //初始化网关限流规则
initGatewayRules();
// //自定义限流异常处理器
initBlockRequestHandler();
}
private void initCustomizedApis() {
Set definitions = new HashSet<>();
// 资源保护名user_service_api Path:/user/**
ApiDefinition api = new ApiDefinition("user_service_api")
.setPredicateItems(new HashSet() {{
add(new ApiPathPredicateItem().setPattern("/user/**")
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(api);
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
private void initGatewayRules() {
Set rules = new HashSet<>();
//resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
//count:限流阈值
//intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
rules.add(new GatewayFlowRule("user_service_api")
.setCount(2)
.setIntervalSec(1)
);
// 加载网关规则
GatewayRuleManager.loadRules(rules);
}
private void initBlockRequestHandler() {
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono handleRequest(ServerWebExchange exchange, Throwable t) {
HashMap result = new HashMap<>();
result.put("code",String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
result.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(result));
}
};
//设置自定义异常处理器
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
(2)访问127.0.0.1:8888/user/findOrderByUserId/1 查看控制台
3.测试 快速点击127.0.0.1:8888/user/findOrderByUserId/1 出现降级
其实我们在流控规则控制台查看并没有我们手动设置的流控规则,这是一个坑,是因为我们应该导入另外一个包就可以配置
2.3.5.3 Gateway整合Sentinel1.pom 把上边的适配包去掉 更换为整合包
com.alibaba.cloud spring-cloud-alibaba-sentinel-gateway
2.重新启动Sentinel控制台,发现我们的菜单发生改变
3.配置流控规则,界面也和我们之前的界面不一样
4.新增一个API流控规则
添加API分组
添加流控规则
5.测试 访问127.0.0.1:8888/user/findOrderByUserId/1 流控成功



