特性
==
gateway的诞生是因为zuul2.0一直跳票,既然这样gateway可以说是zuul的替代品。既然是替代品功能肯定是包含了zuul的。
前置条件
====
SpringCloud Gateway是基于webflux的非阻塞式的网关。 所以gateway的环境要求 Springboot 2.x+、spring webflux、project reactor
因为是非阻塞式,所以和我们之前的阻塞式框架会有所不同。
专业名词
名词
解释
Route
网关的基本组成部分。它由一个ID、一个目标URI、一组谓词和一组过滤器定义。如果聚合谓词为真,则匹配路由
Predicate
这是一个Java 8函数谓词。输入类型是Spring Framework serverwebeexchange。这允许您匹配HTTP请求中的任何内容,比如头或参数
Filter
这些是使用特定工厂构造的GatewayFilter实例。发送下游请求之前或之后修改请求和响应
快速入门
====
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
http://localhost:9091/payment/get/1
会出现8001payment的信息路由规则
Springcloud网关匹配路由作为Spring WebFlux HandlerMapping基础设施的一部分。Spring Cloud Gateway包括许多内置的路由前置工厂。所有这些都匹配HTTP请求的不同属性。我们可以将多个路由谓词工厂与逻辑和语句组合在一起
PathRoutePredicateFactory
来实现的spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- Query=green
http://localhost:9091/payment/get/1
接口将访问不了数据,必须添加green参数 http://localhost:9091/payment/get/1?green
spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- Query=green,\d+
http://localhost:9091/payment/get/1?green=123s
不能访问 , http://localhost:9091/payment/get/1?green=123
则可以spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- Query=green,\d+
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
- RemoteAddr=10.0.20.132/140
10.0.20.132-10.0.20.140
这个段的ip都可以访问- Cookie=zxhtom, hello
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
http://localhost:9091/cloud-payment-service/payment/get/2
过滤器
CLOUD-PAYMENT-SERVICE
、CLOUD-ORDER-SERVICE
这些微服务默认代理为payment
、order
的服务前缀。在gateway中他也为我们提供了相同的功能即服务转发。但是他是针对具体的微服务的。我们可以通过自定义全局过滤器来实现zuul中的功能。下面我们来试试通过RewiritePathGatewayFilterFactory
实现它 - id: order
uri: lb://CLOUD-ORDER-SERVICE
predicates:
- Query=green
filters:
- RewritePath=/order/(?<segment>.*), /$\{segment}
PrefixPathGatewayFilterFactory
是在我们匹配接口上统一加上前缀。比如如下配置 - id: pre_route
uri: http://localhost:8001
predicates:
- Path=/getTimeOut/**
filters:
- PrefixPath=/payment
http://localhost:9091/getTimeOut/123
访问这个接口的时候,我们首先通过routes 中配置匹配到pre_route
然后在接口前添加payment然后路由到真实服务上。 这里需要注意的是我们的匹配是从上至下的所以我们配置的时候注意下顺序 - id: pre_route
uri: http://localhost:8001
predicates:
- Path=/zxhtom/**
filters:
- StripPrefix=2
http://localhost:9091/zxhtom/lqj/payment/getTimeOut/123
实际上会转发到http://localhost:8001/payment/getTimeOut/123
上。注意我们uri的协议,如果是lb表示是服务发现。这里我们配置的是单节点 - id: pre_route3
uri: http://localhost:8001
predicates:
- Path=/hello/{segment}
filters:
- SetPath=/payment/get/{segment}
http://localhost:9091/hello/123
转发到http://localhost:8081/payment/get/123
上自定义网关过滤器
RewritePathGatewayFilterFactory
这些过滤器在配置的时候是配置成RewritePath
后面的GatewayFilterFactory
是没有的。@Component
public class LoginPathGatewayFilterFactory extends AbstractGatewayFilterFactory<LoginPathGatewayFilterFactory.Config> {
public LoginPathGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchage,chain)->{
String userName = config.getUserName();
String password = config.getPassword();
String requestUserName = exchage.getRequest().getQueryParams().getFirst("userName");
String requestPassword = exchage.getRequest().getQueryParams().getFirst("password");
if (userName.equals(requestUserName) && password.equals(requestPassword)) {
return chain.filter(exchage);
} else {
throw new RuntimeException("用户名错误密码。。。。");
}
};
}
public static class Config {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public Config setUserName(String userName) {
this.userName = userName;
return this;
}
public String getPassword() {
return password;
}
public Config setPassword(String password) {
this.password = password;
return this;
}
}
}
- id: pre_route4
uri: http://localhost:8001
predicates:
- Path=/login/{segment}
filters:
- name: LoginPath
args:
userName: zxhtom
password: test
- SetPath=/payment/get/{segment}
GatewayFilter
对象。实际上GatewayFilter
才是真正参与过滤的对象。@Component
public class CustomLoginGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("我进过滤器啦。。。");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customRouteLocator(CustomLoginGatewayFilter customLoginGatewayFilter,RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/baidu")
.uri("https://www.baidu.com")
.filter(customLoginGatewayFilter))
.build();
}
}
自定义全局过滤器
WebsocketRoutingFilter
是gateway内置的,他的实现和网关过滤器其中一种方式一样。@Slf4j
@Component
public class GlobalCustomRoutingFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("我是全局过滤器。。。。。。");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
过滤器名称
限流
gateway
的用法即合成方向。但是作为网站的门户性接口流量比其他服务都大的很多。其他服务正常情况我们会依赖于hystrix
来实现对服务的降级等操作。同样我们也可以在网关层面上加入hystrix来实现服务的高可用。 但是除了hystrix以外, gateway
本身内置了限流算法。下面我们来简单实现下限流。<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
@Component
public class HostAddrKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
//根據服务地址限流
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
@Bean
KeyResolver apiKeyResolver() {
//按URL限流
return exchange -> Mono.just(exchange.getRequest().getPath().toString());
}
@Bean
KeyResolver userKeyResolver() {
//按用户限流
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userName"));
}
}
整合hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@RequestMapping("")
public String fallback(){
return "error";
}
}
总结
==
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。