Spring Cloud Gateway is built upon Spring Boot 2.0, Spring WebFlux, and Project Reactor. As a consequence many of the familiar synchronous libraries (Spring Data and Spring Security, for example) and patterns you may not apply when using Spring Cloud Gateway. If you are unfamiliar with these projects we suggest you begin by reading their documentation to familiarize yourself with some of the new concepts before working with Spring Cloud Gateway.html
必需要补 Spring WebFlux 和 Project Reactor 的技术java
Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux. It does not work in a traditional Servlet Container or built as a WAR.react
Netty 也要补web
依赖:正则表达式
以前学的东西都直接用进来,去服务发现上注册,从集中配置上拉配置文件redis
<!-- 网关依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
配置(bootstrap.yml):spring
server: port: 9001 spring: application: name: gateway-server profiles: active: dev cloud: config: label: master profile: ${spring.profiles.active} discovery: service-id: config-server enabled: true eureka: client: service-url: defaultZone: http://127.0.0.1:8761/eureka/
启动类:bootstrap
@SpringCloudApplication @RestController public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } @Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { return builder.routes() .route(p -> p .path("/get") .filters(f -> f.addRequestHeader("Hello", "World")) .uri("http://localhost:4001/config/param")) .build(); } }
Route:路由网关的基本构建块。它由ID,目标URI,谓词集合和过滤器集合定义。若是聚合谓词为真,则匹配路由缓存
Predicate:这是一个Java 8函数断言。输入类型是Spring Framework ServerWebExchange
。这容许开发人员匹配来自HTTP请求的任何内容,例如标头或参数。cookie
Filters:这些是使用特定工厂构建的Spring Framework GatewayFilter
实例。这里,能够在发送下游请求以前或以后修改请求和响应。
工做流程:
客户端向Spring Cloud Gateway发出请求。若是网关处理程序映射肯定请求与路由匹配,则将其发送到网关Web处理程序。此处理程序运行经过特定于请求的过滤器链发送请求。滤波器被虚线划分的缘由是滤波器能够在发送代理请求以前或以后执行逻辑。执行全部“预”过滤器逻辑,而后进行代理请求。在发出代理请求以后,执行“post”过滤器逻辑。
在没有端口的路由中定义的URI将分别为HTTP和HTTPS URI获取默认端口设置为80和443。
Spring Cloud Gateway将路由做为Spring WebFlux
HandlerMapping
基础结构的一部分进行匹配。Spring Cloud Gateway包含许多内置的Route Predicate工厂。全部这些 Predicate 都匹配HTTP请求的不一样属性。多路线谓词工厂能够组合并经过逻辑组合and
。
Predicate来自于java8的接口。Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将Predicate组合成其余复杂的逻辑(好比:与,或,非)。能够用于接口请求参数校验、判断新老数据是否有变化须要进行更新操做。add–与、or–或、negate–非。
配置:
spring: cloud: gateway: routes: - id: after_route uri: https://example.org predicates: - After=2017-01-20T17:42:47.789-07:00[America/Denver]
内置的Predicate
一、请求时间匹配
二、Cookie匹配
chocolate
who的值与ch.p
正则表达式匹配的cookie三、Header匹配
X-Request-Id
其值与\d+
正则表达式匹配(具备一个或多个数字的值),则此路由匹配四、Host匹配
Host
header has the value www.somehost.org
or beta.somehost.org
or www.anotherhost.org
.sub
如上例中定义的)提取为名称和值的映射,并将其放在ServerWebExchange.getAttributes()
带有定义的键的位置ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
五、Method匹配
六、Path匹配
/foo/1
or /foo/bar
or /bar/baz
.segment
如上例中定义的)提取为名称和值的映射,并将其放在ServerWebExchange.getAttributes()
带有定义的键的位置ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE
七、QueryParam匹配
baz
query parameter.foo
其值与ba.
regexp 匹配的查询参数,则此路由将匹配,所以bar
而且baz
将匹配八、Remote匹配
192.168.1.10
.****示例:
一、时间匹配
@Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { ZonedDateTime zonedDateTime = ZonedDateTime.now().plusDays(-1); String url = "http://localhost:4001/config/param"; return builder.routes() .route("before-predicate", predicateSpec -> predicateSpec .before(zonedDateTime) .uri(url)) .build(); }
二、Cookie匹配
@Bean public RouteLocator routers(RouteLocatorBuilder builder) { String url = "http://localhost:4001/config/param"; return builder.routes() .route(predicateSpec -> predicateSpec .cookie("cookieName", "^\\d+$") .uri(url)) .build(); }
三、Host匹配
@Bean public RouteLocator routers(RouteLocatorBuilder builder) { String url = "http://localhost:4001/config/param"; return builder.routes() .route(predicateSpec -> predicateSpec.host("localhost").uri(url)) .build(); }
4 ...
一、按执行顺序分
pre过滤器:转发以前执行。参数校验、权限校验、流量监控、日志输出、协议转换等
post过滤器:转发以后执行。响应内容、响应头的修改,日志的输出,流量监控等
二、按做用范围分
global filter:全部路由
gateway filter:指定的路由
一、AddRequestHeaderGatewayFilterFactory:在匹配的请求上添加请求头,如示例中,添加请求头:X-Request-Foo;值:bar
spring: cloud: gateway: routes: - id: add_request_parameter_route uri: https://example.org filters: # 添加请求头 X-Request-Foo:Bar - AddRequestParameter=X-Request-Foo, Bar
二、AddRequestParameterGatewayFilterFactory:在匹配的请求上添加请求参数
spring: cloud: gateway: routes: - id: add_request_parameter_route uri: https://example.org filters: # 添加请求参数 foo=bar; 在query串中添加 - AddRequestParameter=foo, bar
三、AddResponseHeaderGatewayFilterFactory:在匹配的请求上添加响应头
spring: cloud: gateway: routes: - id: add_response_header_route uri: https://example.org filters: # 添加响应头 X-Response-Foo:Bar - AddResponseHeader=X-Response-Foo, Bar
四、HystrixGatewayFilterFactory:将断路器引入网关路由
spring: cloud: gateway: routes: - id: hystrix_route uri: https://example.org filters: - Hystrix=myCommandName
五、HystrixGatewayFilterFactory:将断路器引入网关路由,保护您的服务免受级联故障的影响,并容许您在下游故障时提供回退响应。
六、PrefixPathGatewayFilterFactory:将为/mypath
全部匹配请求的路径添加前缀
七、PreserveHostHeaderGatewayFilterFactory:设置路由过滤器将检查的请求属性,以肯定是否应发送原始主机头,而不是http客户端肯定的主机头。
八、RequestRateLimiterGatewayFilterFactory:RateLimiter
实现来肯定是否容许当前请求继续。若是不是,HTTP 429 - Too Many Requests
则返回(默认状况下)状态。
九、RedirectToGatewayFilterFactory: takes a status
and a url
parameter. The status should be a 300 series redirect http code, such as 301. The url should be a valid url. This will be the value of the Location
header
十、RemoveRequestHeaderGatewayFilterFactory:接受一个name
参数。它是要删除的标头的名称
十一、RemoveResponseHeaderGatewayFilterFactory:接受一个name
参数。它是要删除的标头的名称
十二、...
全部实例
GlobalFilter
和全部路由特定实例添加GatewayFilter
到过滤器链中。这个组合的过滤器链按org.springframework.core.Ordered
接口排序,能够经过实现getOrder()
方法或使用@Order
注释来设置。
一、LoadBalancerClientFilter:交换属性查找一个URI ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
。若是url有一个lb
方案(即lb://myservice
),它将使用Spring Cloud LoadBalancerClient
将名称(myservice
在前面的示例中)解析为实际的主机和端口,并替换相同属性中的URI。未修改的原始URL将附加到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中的列表中。过滤器还将查看ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
属性以查看它是否等于lb
,而后应用相同的规则。
二、...
The Gateway can be configured to create routes based on services registered with a DiscoveryClient
compatible service registry.
一、set spring.cloud.gateway.discovery.locator.enabled=true
and make sure a DiscoveryClient
implementation is on the classpath and enabled (such as Netflix Eureka, Consul or Zookeeper).
二、Configuring Predicates and Filters For DiscoveryClient Routes
三、自定义DiscoveryClient
路由使用的谓词和/或过滤器,能够经过设置spring.cloud.gateway.discovery.locator.predicates[x]
和来自定义spring.cloud.gateway.discovery.locator.filters[y]
。
spring.cloud.gateway.discovery.locator.predicates[0].name:Path spring.cloud.gateway.discovery.locator.predicates[0].args [pattern]:“'/'+ serviceId +'/ **'” spring.cloud.gateway.discovery.locator.predicates[1].name:Host spring.cloud.gateway.discovery.locator.predicates[1].args [pattern]:“'**。foo.com'” spring.cloud.gateway.discovery.locator.filters[0].name:Hystrix spring.cloud.gateway.discovery.locator.filters[0].args [name]:serviceId spring.cloud.gateway.discovery.locator.filters[1].name:RewritePath spring.cloud.gateway.discovery.locator.filters[1].args [regexp]:“'/'+ serviceId +'/(?<remaining>.*)'” spring.cloud.gateway.discovery.locator.filters[1].args [replacement]:“'/ $ {remaining}'”
监控端点:
GET /actuator/gateway/globalfilters:检索应用于全部路由的全局过滤器
GET /actuator/gateway/routefilters:查看路由过滤器
POST /actuator/gateway/refresh:刷新路由缓存
GET /actuator/gateway/routes:检索网关中定义的路由
GET /actuator/gateway/routes/{id}:检索特定路径的路由信息
POST/DELETE /gateway/routes/{id_route_to_create}:建立或删除特定路由
一、初始化路由
不管是yml仍是代码,这些配置最终都是被封装到RouteDefinition对象中。
一个RouteDefinition有个惟一的ID,若是不指定,就默认是UUID,多个RouteDefinition组成了gateway的路由系统。
全部路由信息在系统启动时就被加载装配好了,并存到了内存里
涉及到的相关bean
RouteDefinitionRepository: 从存储器中加载路由
public interface RouteDefinitionLocator { Flux<RouteDefinition> getRouteDefinitions(); }
二、实现本身的加载逻辑,这里从redis中加载
添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>
建立RedisRouteDefinitionRepository,实现RouteDefinitionRepository
@Component @Slf4j @AllArgsConstructor @SuppressWarnings("all") public class RedisRouteDefinitionRepository implements RouteDefinitionRepository { private static final String ROUTE_KEY = "gateway_route_key"; private final RedisTemplate redisTemplate; @Override public Flux<RouteDefinition> getRouteDefinitions() { redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(RouteDefinition.class)); List<RouteDefinition> values = redisTemplate.opsForHash().values(ROUTE_KEY); log.debug("redis 中路由定义条数: {}, {}", values.size(), values); return Flux.fromIterable(values); } @Override public Mono<Void> save(Mono<RouteDefinition> route) { return route.flatMap(r -> { log.info("保存路由信息{}", r); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.opsForHash().put(ROUTE_KEY, r.getId(), r); return Mono.empty(); }); } @Override public Mono<Void> delete(Mono<String> routeId) { routeId.subscribe(id -> { log.info("删除路由信息{}", id); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.opsForHash().delete(ROUTE_KEY, id); }); return Mono.empty(); } }
路由的定义能够任何来源初始化到redis,这里只模拟
@PostConstruct public void main() { RouteDefinition definition = new RouteDefinition(); definition.setId("id"); URI uri = UriComponentsBuilder.fromHttpUrl("http://localhost:4001/config/param").build().toUri(); definition.setUri(uri); //定义第一个断言 PredicateDefinition predicate = new PredicateDefinition(); predicate.setName("Path"); Map<String, String> predicateParams = new HashMap<>(8); predicateParams.put("pattern", "/get"); predicate.setArgs(predicateParams); //定义Filter FilterDefinition filter = new FilterDefinition(); filter.setName("AddRequestHeader"); Map<String, String> filterParams = new HashMap<>(8); //该_genkey_前缀是固定的,见org.springframework.cloud.gateway.support.NameUtils类 filterParams.put("_genkey_0", "header"); filterParams.put("_genkey_1", "addHeader"); filter.setArgs(filterParams); FilterDefinition filter1 = new FilterDefinition(); filter1.setName("AddRequestParameter"); Map<String, String> filter1Params = new HashMap<>(8); filter1Params.put("_genkey_0", "param"); filter1Params.put("_genkey_1", "addParam"); filter1.setArgs(filter1Params); definition.setFilters(Arrays.asList(filter, filter1)); definition.setPredicates(Arrays.asList(predicate)); System.out.println("definition:" + JSONUtil.toJsonStr(definition)); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(RouteDefinition.class)); redisTemplate.opsForHash().put(ROUTE_KEY, "router1", definition); }
启动网关,装配RedisRouteDefinitionRepository后,spring调用main(),建立一条路由
GET /actuator/gateway/routes:查看当前路由信息
三、也可使用http请求实现,这里就不写了。