第一章 Java线程池技术应用
第二章 CountDownLatch和Semaphone的应用
第三章 Spring Cloud 简介
第四章 Spring Cloud Netflix 之 Eureka
第五章 Spring Cloud Netflix 之 Ribbon
第六章 Spring Cloud 之 OpenFeign
第七章 Spring Cloud 之 GateWay

API 网关是一个搭建在客户端和微服务之间的服务,我们可以在 API 网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。

基于上一章节的内容,已经集成了Spring Cloud Netflix微服务组件。其中服务发现、注册组件:Eureka,服务远程调用、负载均衡组件:OpenFeign。
本章节在DNS、Nginx层之后加入网关层,通过Nginx + GateWay 去访问服务。 网关层可以做路由、限流、权限验证、请求过滤等操作。

而在定义转发规则时主要涉及了以下三个核心概念,如下表。
| 核心概念 | 描述 | 
|---|---|
| Route(路由) | 网关最基本的模块。它由一个 ID、一个目标 URI、一组断言(Predicate)和一组过滤器(Filter)组成。 | 
| Predicate(断言) | 路由转发的判断条件,我们可以通过 Predicate 对 HTTP 请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务。 | 
| Filter(过滤器) | 过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。 | 

pring Cloud Gateway 通过 Predicate 断言来实现 Route 路由的匹配规则。简单点说,Predicate 是路由转发的判断条件,请求只有满足了 Predicate 的条件,才会被转发到指定的服务上进行处理。

常见的 Predicate 断言如下表(假设转发的 URI 为 http://localhost:8001)。
| 断言 | 示例 | 说明 | 
|---|---|---|
| Path | - Path=/user/listUserInfo/** | 当请求路径与 /user/listUserInfo/** 匹配时,该请求才能被转发到 http://localhost:8001 上。 | 
| Before | - Before=2022-12-07T11:47:34.255+08:00[Asia/Shanghai] | 在 2022 年 12 月 07 日 11 时 47 分 34.255 秒之前的请求,才会被转发到 http://localhost:8001 上。 | 
| After | - After=2022-12-07T11:47:34.255+08:00[Asia/Shanghai] | 在 2022 年 12 月 07 日 11 时 47 分 34.255 秒之后的请求,才会被转发到 http://localhost:8001 上。 | 
| Between | - Between=2022-12-07T15:18:33.226+08:00[Asia/Shanghai],2022-12-07T15:23:33.226+08:00[Asia/Shanghai] | 在 2022 年 12 月 07 日 15 时 18 分 33.226 秒 到 2022 年 12 月 07 日 15 时 23 分 33.226 秒之间的请求,才会被转发到 http://localhost:8001 服务器上。 | 
| Cookie | - Cookie=name,kelvin.com | 携带 Cookie 且 Cookie 的内容为 name=kelvin.com 的请求,才会被转发到 http://localhost:8001 上。 | 
| Header | - Header=X-Request-Id,\d+ | 请求头上携带属性 X-Request-Id 且属性值为整数的请求,才会被转发到 http://localhost:8001 上。 | 
| Method | - Method=GET | 只有 GET 请求才会被转发到 http://localhost:8001 上。 | 
建立子模块:gateway-service
4.0.0 com.kelvin SpringCloud 0.0.1-SNAPSHOT gateway-service 8 8 UTF-8 org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-starter-gateway 
server:
  port: 80
spring:
  application:
    name: gateway-service
  cloud:
    gateway: #网关路由配置
      routes:
        #将 drp-user-service 提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址 80
        - id: drp-user-service_routh   #路由 id,没有固定规则,但唯一,建议与服务名对应
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            #以下是断言条件,必选全部符合条件
            - Path=/user/userInfoList/**               #断言,路径匹配 注意:Path 中 P 为大写
            - Method=GET #只能时 GET 请求时,才能访问
eureka:
  instance:
    instance-id: gateway-service
    hostname: localhost
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://localhost:7001/eureka
 
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class,args);
    }
}
 
访问:http://localhost/user/userInfoList
以服务名(spring.application.name)作为路径创建动态路由进行转发,从而实现动态路由功能
Route 的 uri 地址修改为以下形式。
lb://service-name
server:
  port: 80
spring:
  application:
    name: drp-gateway-service
  cloud:
    gateway: #网关路由配置
      routes:
        #将 drp-user-service 提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址 80
        - id: drp-user-service_routh   #路由 id,没有固定规则,但唯一,建议与服务名对应
          uri: lb://USER-SERVICE          #匹配后提供服务的路由地址
          predicates:
            #以下是断言条件,必选全部符合条件
            - Path=/user/userInfoList/**               #断言,路径匹配 注意:Path 中 P 为大写
            - Method=GET #只能时 GET 请求时,才能访问
          metadata:
             connect-timeout: 10
             #单位毫秒
             response-timeout: 10000
eureka:
  instance:
    instance-id: drp-gateway-service
    hostname: localhost
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
     defaultZone: http://localhost:7001/eureka
 
用户登陆状态校验、签名校验。
Spring Cloud Gateway 提供了以下两种类型的过滤器
| 过滤器类型 | 说明 | 
|---|---|
| Pre 类型 | 这种过滤器在请求被转发到微服务之前可以对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等操作。 | 
| Post 类型 | 这种过滤器在微服务对请求做出响应后可以对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。 | 
按照作用范围划分,Spring Cloud gateway 的 Filter 可以分为 2 类:GatewayFilter、GlobalFilter
应用在单个路由或者一组路由上的过滤器。
常用的GatewayFilter过滤器
| 路由过滤器 | 描述 | 参数 | 使用示例 | 
|---|---|---|---|
| AddRequestHeader | 拦截传入的请求,并在请求上添加一个指定的请求头参数。 | name:需要添加的请求头参数的 key value:需要添加的请求头参数的 value。 | - AddRequestHeader=my-request-header,1024 | 
| AddRequestParameter | 拦截传入的请求,并在请求上添加一个指定的请求参数。 | name:需要添加的请求参数的 key; value:需要添加的请求参数的 value。 | - AddRequestParameter=my-request-param,c.biancheng.net | 
| AddResponseHeader | 拦截响应,并在响应上添加一个指定的响应头参数。 | name:需要添加的响应头的 key; value:需要添加的响应头的 value。 | - AddResponseHeader=my-response-header,c.biancheng.net | 
| PrefixPath | 拦截传入的请求,并在请求路径增加一个指定的前缀。 | prefix:需要增加的路径前缀。 | -PrefixPath=/consumer | 
| PreserveHostHeader | 转发请求时,保持客户端的 Host 信息不变,然后将它传递到提供具体服务的微服务中。 | 无 | -PreserveHostHeader | 
| RemoveRequestHeader | 移除请求头中指定的参数。 | name:需要移除的请求头的 key。 | - RemoveRequestHeader=my-request-header | 
| RemoveResponseHeader | 移除响应头中指定的参数。 | name:需要移除的响应头。 | - RemoveResponseHeader=my-response-header | 
| RemoveRequestParameter | 移除指定的请求参数。 | name:需要移除的请求参数。 | - RemoveRequestParameter=my-request-param | 
| RequestSize | 配置请求体的大小,当请求体过大时,将会返回 413 Payload Too Large。 | maxSize:请求体的大小。 | - name:RequestSize args: maxSize: 5000000 | 
spring:
  application:
    name: drp-gateway-service
  cloud:
    gateway: #网关路由配置
      routes:
        #将 drp-user-service 提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址 80
        - id: drp-user-service_routh   #路由 id,没有固定规则,但唯一,建议与服务名对应
          uri: lb://USER-SERVICE          #匹配后提供服务的路由地址
          predicates:
            #以下是断言条件,必选全部符合条件
            - Path=/userInfoList/**               #断言,路径匹配 注意:Path 中 P 为大写
            - Method=GET #只能时 GET 请求时,才能访问
          filters:
            - AddRequestHeader=token
            - PrefixPath=/user
 
应用在所有的路由上的过滤器,可用于统一异常处理
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
/***
 * @title DrfGlobalFilter
 * @desctption 登录验证
 * @author kelvin
 * @create 2023/5/15 14:17
 **/
@Component
public class DrfGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //获取URI地址
        RequestPath path = request.getPath();
        HttpHeaders headers = request.getHeaders();
        List stringList = headers.get("token");
        //是否登录验证
        if(CollectionUtils.isEmpty(stringList)){
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        //过滤器优先级,0为最高
        return 0;
    }
}
   
本章节成功的在Spring Cloud Netflix生态上集成了GateWay,基于DNS(域名解析) + Nginx(反向代理) + gateway + Eureka等的微服务架构,能解决安全、路由、限流、请求过滤、流量计费等问题。下一章节我们给大家带来Spring Cloud Netflix框架提供的限流组件Hystrix的功能介绍和使用。