1、API Gateway简单介绍
1.1 什么是API网关?
API网关是所有请求的入口,承载了所有的流量,API Gateway是一个门户一样,也可以说是进入系统的唯一节点。这跟面向对象设计模式中的Facet模式很像。API Gateway封装内部系统的架构,并且提供API给各个客户端。它还可能有其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等
画图表示,没有网关的情况,客户端的请求会直接落到后端的各个服务中,无法集中统一管理
画图表示,有网关的情况,所有的请求都先经过网关,然后进行分发到对应服务
1.2 API网关的作用
网关可以用于授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等,挑几个介绍
- 动态路由
网关可以做路由转发,假如服务信息变了,只要改网关配置既可,所以说网关有动态路由(Dynamic Routing)的作用,如图:
- 请求监控
请求监控可以对整个系统的请求进行监控,详细地记录请求响应日志,如图,可以将日志丢到消息队列,如果没有使用网关的话,记录请求信息需要在各个服务中去做
- 认证鉴权
认证鉴权可以对每一个访问请求做认证,拒绝非法请求,保护后端的服务,不需要每个服务都做鉴权,在项目中经常有加上OAuth2.0、JWT,Spring Security进行权限校验
- 压力测试
有网关的系统,如果要要对某个服务进行压力测试,可以如图所示,改下网关配置既可,测试请求路由到测试服务,测试服务会有单独的测试数据库,这样测试的请求就不会影响到正式的服务和数据库
2、SpringCloud Gateway
2.1 What is SpringCloud Gateway?
用公网的解释是:SpringCloud Gateway是一个在Spring生态系统之上构建的API网关,包括:Spring 5,Spring Boot 2,Project Reactor(基于高性能的Reactor模式响应式通信框架Netty,异步阻塞模型)。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注,例如:安全性,监视/度量和弹性。
SpringCloud Gateway采用了WebFlux,所以使用时不需要引入web场景启动器对应jar,而需要依赖于WebFlux,当然高版本,肯定不需要自己引入,在对应的starter已经集成
2.2 SpringCloud Gateway结构
引用官方图例如图,SpringCloud Gateway的底层基于Netty,主要组成有Predicates(谓词或者断言)、Route(路由)、Filter(过滤器)

画张思维导图表示SpringCloud Gateway的组成:
- 路由(route):网关的基本构建块。它由ID,目标URI,谓词集合和过滤器集合定义
- 过滤器(Filter):这些过滤器是使用特定工厂构造的Spring Framework
GatewayFilter实例 - 谓词(Predicates): 引用了java8的函数谓词,输入类型是Spring Framework
ServerWebExchange。谓词可以匹配HTTP请求中的所有内容,例如标头或参数
2.3 SpringCloud Gateway工作方式
从总体上概述了Spring Cloud Gateway的工作方式,引用官网的图例:

从官网的图来看,并不是特别复杂,首先客户端请求都会先经过Gateway Handler Mapping,匹配上就通过Gateway Web Handler转给过滤器处理,过滤器分为PreFilter(前置过滤器)、PostFilter(后置过滤器)。过滤器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑。所有“前置”过滤器逻辑均被执行。然后发出代理请求。发出代理请求后,将运行“后置”过滤器逻辑
3、Gateway实验环境准备
环境准备:
- JDK 1.8
- SpringBoot2.2.3
- SpringCloud(Hoxton.SR7)
- Maven 3.2+
开发工具
- IntelliJ IDEA
- smartGit
新增SpringBoot Initializer项目:New Module->Spring Initializer,选择jdk版本,至少jdk8

packaging选择jar,java version选择jdk8的,然后点next
选择Gateway的依赖,选择之后会自动加上对应pom配置
Eureka客户端的依赖也可以加上,这样就可以注册服务到eureka服务端
新建项目之后,检查pom是否有spring-cloud-starter-gateway<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>
检查pom是否有spring-cloud-starter-netflix-eureka-client
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>
如果不通过idea的Spring Initializer新建项目的,需要自己加上:
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>
本博客的是基于spring-cloud-starter-netflix-eureka-client进行试验,试验前要运行eureka服务端,eureka服务提供者,代码请参考上一章博客
4、API Gateway简单实现
4.1 YAML配置Eureka和Gateway
Eureka客户端配置:ps,注意在Application加上@EnableEurekaClient
eureka:client:# 配置eureka服务地址service-url:defaultZone: http://localhost:8761/eureka/# 关闭eureka健康检查healthcheck:enabled: false# Eureka服务注册开启register-with-eureka: true# Eureka服务发现开启fetch-registry: trueinstance:status-page-url-path: http://localhost:8761/actuator/infohealth-check-url-path: http://localhost:8761/actuator//health# 显示ipprefer-ip-address: true# eureka实例idinstance-id: api-gateway8082
API Gateway配置:
spring:application:# 指定application namename: api-gatewaycloud:gateway:routes:# 路由id- id: user-service-provider# 路由到的地址uri: http://127.0.0.1:8083/api/users/{username}# 设置谓词,路径匹配的进行路由predicates:- Path=/api/users/{username}
可能遇到:Unable to find RoutePredicateFactory with name Path ,谓词Path必须大写,而且等号之间不能有空格
4.2 Bean注册方式配置网关
除了配置文件,也可以通过配置类进行网关配置:
package com.example.springcloud.gateway.configuration;import org.springframework.cloud.gateway.route.RouteLocator;import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/*** <pre>* spring cloud gateway configuration* </pre>** <pre>* @author mazq* 修改记录* 修改后版本: 修改人: 修改日期: 2020/09/14 15:00 修改内容:* </pre>*/@Configurationpublic class GatewayConfiguration {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {return routeLocatorBuilder.routes().route("user-service-provider1",r->r.path("/api/findUser").uri("http://127.0.0.1:8083/api/findUser")).build();}}
4.3 CURL测试Gateway的接口
curl http://127.0.0.1:gateway_port/api/users/admin
5、Gateway谓词工厂分类
SpringCloud Gateway的谓词工厂分类如图,所谓谓词或者说断言,其实就是一种匹配的规则,根据这些匹配,匹配到就经过过滤器
SpringCloud Gateway的谓词分类比较多,在SpringCloud官方手册也有进行比较详细的介绍,所以本文章挑几个进行介绍既可
- After谓词配置
在指定的datetime后触发过滤器
spring:cloud:gateway:routes:- id: after_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- After=2019-01-01T16:30:00+08:00[Asia/Shanghai]
Before谓词配置
spring:cloud:gateway:routes:- id: before_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Before=2018-01-01T16:30:00+08:00[Asia/Shanghai]
Between谓词配置 ```yaml spring: cloud: gateway:
routes:- id: between_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Between=2018-01-01T16:30:00+08:00[Asia/Shanghai], 2019-01-01T16:30:00+08:00[Asia/Shanghai]
- Cookie谓词配置加上cookie "chocolate=ch.p" 经过过滤器```yamlspring:cloud:gateway:routes:- id: cookie_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Cookie=chocolate, ch.p
linux curl测试接口:
curl http://192.168.9.10:8082/api/findUser?username=nicky --cookie "chocolate=ch.p"

- Header谓词配置
加上请求头参数“X-Request-Id”, \d+标识数字
spring:cloud:gateway:routes:- id: header_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Header=X-Request-Id, \d+
curl http://192.168.9.10:8082/api/findUser?username=nicky -H "X-Request-Id:123"
- HOST谓词配置
加上域名host匹配
spring:cloud:gateway:routes:- id: host_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Host=**.csdn.net
curl http://192.168.9.10:8082/api/findUser?username=nicky -H "Host:smilenicky.csdn.net"
- Method谓词配置
method是http请求方式,eg:GET、POST、PUT等等
spring:cloud:gateway:routes:- id: method_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Method=GET
curl -X POST http://192.168.9.30:8082/api/findUser?username=nicky{"timestamp":"2020-09-15T02:37:30.224+00:00","status":405,"error":"Method Not Allowed","message":"","path":"/api/findUser"}
- Query谓词配置
请求参数匹配,url?username=???
spring:cloud:gateway:routes:- id: query_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Query=username
curl http://192.168.9.30:8082/api/findUser?username=nicky
- 远程地址谓词
在远程机192.168.1.1调用接口,都会匹配
spring:cloud:gateway:routes:- id: remoteaddr_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- RemoteAddr=192.168.1.1/22
curl http://192.168.9.30:8082/api/findUser?username=nicky
- 权重谓词配置
权重匹配比较像nginx的权重配置,8083 url接收80%的请求,8084接收20%请求
spring:cloud:gateway:routes:- id: weight_highuri:http://127.0.0.1:8083predicates:- Weight=group1, 8- id: weight_lowuri: http://127.0.0.1:8084predicates:- Weight=group1, 2
curl http://192.168.9.30:8082/api/findUser?username=nicky
6、Gateway过滤器类型分类
7、GatewayFilter工厂分类
SpringCloud的gatewayFilter有很多分类,详情参考官方手册,官方手册的介绍也相对比较详细,所以本博客挑几个介绍:
- PrefixPath GatewayFilter
这个网关过滤器是在请求链接时候加上前缀,如下配置,加上/api的前缀
spring:cloud:gateway:routes:- id: prefixpath_routeuri: http://127.0.0.1:8083filters:- PrefixPath=/api
curl http://192.168.9.30:8082/findUser?username=nicky
相当于:
curl http://192.168.9.30:8082/api/findUser?username=nicky
- AddRequestParameter GatewayFilter
AddRequestParameter GatewayFilter自动带上请求参数的过滤器,加上username=admin参数
spring:cloud:gateway:routes:- id: add_request_parameter_routeuri: http://127.0.0.1:8083filters:- AddRequestParameter=username, admin
curl http://192.168.9.30:8082/api/findUser
相当于:
curl http://192.168.9.30:8082/api/findUser?username=admin
- Hystrix GatewayFilter
Hystrix分布式服务容错保护的过滤器
pom加上配置:
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
写个ResultBean类:
package com.example.springcloud.gateway.bean;import lombok.Data;import org.springframework.http.HttpStatus;/*** <pre>* ResultBean* </pre>** <pre>* @author mazq* 修改记录* 修改后版本: 修改人: 修改日期: 2020/08/10 17:07 修改内容:* </pre>*/@Datapublic class ResultBean {/*** 状态* */private int status;/*** 描述* */private String desc;/*** 数据返回* */private Object data;public ResultBean(int status, String desc, Object data) {this.status = status;this.desc = desc;this.data = data;}public ResultBean(Object data) {this.status = HttpStatus.OK.value();this.desc = "处理成功";this.data = data;}public static ResultBean ok(Object data) {return new ResultBean(data);}public static ResultBean ok() {return new ResultBean(null);}public static ResultBean badRequest(String desc,Object data) {return new ResultBean(HttpStatus.BAD_REQUEST.value(), desc, data);}public static ResultBean badRequest(String desc) {return new ResultBean(HttpStatus.BAD_REQUEST.value(), desc, null);}public static ResultBean serverError(String desc, Object data){return new ResultBean(HttpStatus.INTERNAL_SERVER_ERROR.value(),"服务器内部异常:"+desc,data);}public static ResultBean serverError(String desc){return new ResultBean(HttpStatus.INTERNAL_SERVER_ERROR.value(),"服务器内部异常:"+desc,null);}}
接口出错,回调这个接口,避免一直请求,造成服务雪崩
package com.example.springcloud.gateway.rest.controller;import com.example.springcloud.gateway.bean.ResultBean;import org.springframework.http.HttpStatus;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;/*** <pre>* HystrixRestController* </pre>** <pre>* @author mazq* 修改记录* 修改后版本: 修改人: 修改日期: 2020/09/15 11:46 修改内容:* </pre>*/@RestControllerpublic class HystrixRestController {@GetMapping(value = {"/fallback"})public ResultBean fallback() {return ResultBean.badRequest("Hystrix fallback");}}
加上配置:
spring:cloud:gateway:routes:- id: hystrix_routeuri: http://127.0.0.1:8083/api/findUserpredicates:- Method=GETfilters:- name: Hystrixargs:name: fallbackcmdfallbackUri: forward:/fallback
关了服务请求,让接口报错:
curl http://192.168.9.10:8082/api/findUser?username=nicky{"status":400,"desc":"Hystrix fallback","data":null}
ps:spring cloud gateway:Unable to find GatewayFilterFactory with name Hystrix
项目里有引入eureka客户端,跟其源码,可以指定其实是有引入Hystrix的,所以原本,我就不加上Hystrix配置,不过项目是一直有报错:spring cloud gateway:Unable to find GatewayFilterFactory with name Hystrix,所以maven查看jar,发现eureka client只是引入部分的jar:

所以总的来说,还是要自己配置;
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
- Requestratelimiter GatewayFilter
requestratelimiter用于简单的实现限流,基于Redis实现
@Bean@PrimaryKeyResolver userKeyResolver() {return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));}@Beanpublic KeyResolver ipKeyResolver() {return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}
KeyResolver需要加上@Primary
spring:redis:host: 127.0.0.1password:port: 6379cloud:gateway:routes:## RequestRateLimiter GatewayFilter简单限流- id: requestratelimiter_routeuri: http://192.168.9.30:8083/api/findUserpredicates:- Method=GETfilters:- name: RequestRateLimiterargs:# 每秒允许处理的请求数量redis-rate-limiter.replenishRate: 1# 每秒最大处理的请求数量redis-rate-limiter.burstCapacity: 2#每秒最大处理token数量redis-rate-limiter.requestedTokens: 1# 限流策略,对应策略的BeanNamekey-resolver: "#{@ipKeyResolver}"

- Retry GatewayFilter
retry GatewayFilter是用于重试的过滤器
spring:cloud:gateway:routes:# RetryFilter 重试过滤器- id: retry_testuri: http://127.0.0.1:8083/api/findUserpredicates:- Method=GETfilters:- name: Retryargs:retries: 3 # 重试次数statuses: BAD_GATEWAYmethods: GET,POSTbackoff:firstBackoff: 10msmaxBackoff: 50msfactor: 2basedOnPreviousValue: false
8、GlobalFilter工厂分类介绍
SpringCloud Gateway的GlobalFilter分类如图,详情可以参考官方手册,GlobalFilter是全局的过滤器,作用于所有的路由
8.1 全局过滤器分类
8.2 自定义全局过滤器
package com.example.springcloud.gateway.filter.global;import lombok.extern.slf4j.Slf4j;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;@Slf4jpublic class CustomGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("custom global filter");return chain.filter(exchange);}@Overridepublic int getOrder() {return -1;}}
配置类进行配置:
@Beanpublic GlobalFilter customFilter() {return new CustomGlobalFilter();}

9、SpringCloud官方手册和博客
9.1 SpringCloud Gateway官方手册
- SpringCloud 2.0系列的官方参考手册:
https://docs.spring.io/spring-cloud-config/docs/2.2.x/reference/html/ SpringCloud gateway的官方参考手册:
https://docs.spring.io/spring-cloud-gateway/docs/2.2.x-SNAPSHOT/reference/html9.2 SpringCloud Gateway优质参考博客
方志鹏大佬系列Spring Cloud博客:https://www.fangzhipeng.com/spring-cloud.html
- 使用Spring Cloud与Docker实战微服务:https://eacdy.gitbooks.io/spring-cloud-book/content/
- 程序员DD大佬系列Spring Cloud博客:http://blog.didispace.com/spring-cloud-learning/
- Spring Cloud GateWay 应用 -> 高可用:https://juejin.im/post/6854573221329846280#heading-6
- Spring Cloud Gateway:SpringCloud API网关服务:https://juejin.im/post/6844903982599684103
