这是我参与更文挑战的第1天,活动详情查看: 更文挑战html
本文正在参加「Java主题月 - Java 开发实战」,详情查看 活动连接java
分布式系列之网关zuul包揽全局--不再用东拼西凑各个接口啦web
gateway的诞生是由于zuul2.0一直跳票,既然这样gateway能够说是zuul的替代品。既然是替代品功能确定是包含了zuul的。redis
SpringCloud Gateway是基于webflux的非阻塞式的网关。 因此gateway的环境要求 Springboot 2.x+、spring webflux、project reactor算法
由于是非阻塞式,因此和咱们以前的阻塞式框架会有所不一样。spring
名词 | 解释 |
---|---|
Route | 网关的基本组成部分。它由一个ID、一个目标URI、一组谓词和一组过滤器定义。若是聚合谓词为真,则匹配路由 |
Predicate | 这是一个Java 8函数谓词。输入类型是Spring Framework serverwebeexchange。这容许您匹配HTTP请求中的任何内容,好比头或参数 |
Filter | 这些是使用特定工厂构造的GatewayFilter实例。发送下游请求以前或以后修改请求和响应 |
点我官网快速开始api
新建模块geteway 并制定端口9091数组
引入坐标安全
<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的信息
下面咱们详细来看看gateway的路由规则
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
光有参数仍是不行,加入咱们要求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
复制代码
在zuul中整合服务发现后有默认的路由规则的。一样的gateway也能够接入服务发现这里仍是以eureka为列。
这里有关服务发现的配置我就再也不赘述了。在eureka专题已经介绍了,在hystrix、zuul等专题页有相关的配置,我就直接贴出gateway的开启配置
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
还记得咱们在zuul专题中实现了默认路由转发规则吗,就是将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;
}
}
复制代码
关于限流笔者以前经过redis分别实现目前主流的四种限流算法。有兴趣的能够阅读下,阅读结束别忘记回到本文继续观看gateway哦。别走太远!!!
上面咱们主要在介绍gateway
的用法即合成方向。可是做为网站的门户性接口流量比其余服务都大的不少。其余服务正常状况咱们会依赖于hystrix
来实现对服务的降级等操做。一样咱们也能够在网关层面上加入hystrix来实现服务的高可用。 可是除了hystrix之外, gateway
自己内置了限流算法。下面咱们来简单实现下限流。
提到网关咱们就必定绕不开限流。网关的做用就是代理可是并非没有条件的任性代理。为何保护咱们的模块在网关中会对下游服务进行限流。有些接口处于安全和稳定考虑都会限制流量的
gateway实现限流也很简单。只须要咱们引入redis相关模块在使用内置过滤器就能够了
<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"));
}
}
复制代码
<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";
}
}
复制代码