springcloud gateway_SpringCloud系列之API Gateway开发手册(Hoxton版本)

SpringCloud系列之API Gateway开发手册(Hoxton版本)

SpringCloud系列之API Gateway开发手册(Hoxton版本)​smilenicky.blog.csdn.net
45e30a44a832eba6a20f1d4d2e5a2eed.png

文章目录

  • SpringCloud系列之API Gateway开发手册(Hoxton版本)
    • 1、API Gateway简单介绍
      • 1.1 什么是API网关?
      • 1.2 API网关的作用
    • 2、SpringCloud Gateway
      • 2.1 What is SpringCloud Gateway?
      • 2.2 SpringCloud Gateway结构
      • 2.3 SpringCloud Gateway工作方式
    • 3、Gateway实验环境准备
    • 4、API Gateway简单实现
      • 4.1 YAML配置Eureka和Gateway
      • 4.2 Bean注册方式配置网关
      • 4.3 CURL测试Gateway的接口
    • 5、Gateway谓词工厂分类
    • 6、Gateway过滤器类型分类
    • 7、GatewayFilter工厂分类
    • 8、GlobalFilter工厂分类介绍
      • 8.1 全局过滤器分类
      • 8.2 自定义全局过滤器
    • 9、SpringCloud官方手册和博客
      • 9.1 SpringCloud Gateway官方手册
      • 9.2 SpringCloud Gateway优质参考博客

1、API Gateway简单介绍

1.1 什么是API网关?

API网关是所有请求的入口,承载了所有的流量,API Gateway是一个门户一样,也可以说是进入系统的唯一节点。这跟面向对象设计模式中的Facet模式很像。API Gateway封装内部系统的架构,并且提供API给各个客户端。它还可能有其他功能,如授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等

画图表示,没有网关的情况,客户端的请求会直接落到后端的各个服务中,无法集中统一管理

a2b543c24522ab039f117a16bd32324c.png

画图表示,有网关的情况,所有的请求都先经过网关,然后进行分发到对应服务

2ba3e2ea7dd855b75b6f48add851c3b0.png

1.2 API网关的作用

网关可以用于授权、监控、负载均衡、缓存、请求分片和管理、静态响应处理等,挑几个介绍

  • 动态路由
    网关可以做路由转发,假如服务信息变了,只要改网关配置既可,所以说网关有动态路由(Dynamic Routing)的作用,如图:

2ba3e2ea7dd855b75b6f48add851c3b0.png
  • 请求监控
    请求监控可以对整个系统的请求进行监控,详细地记录请求响应日志,如图,可以将日志丢到消息队列,如果没有使用网关的话,记录请求信息需要在各个服务中去做

9de2a00b8265bf33d70ac93ad40977b0.png
  • 认证鉴权
    认证鉴权可以对每一个访问请求做认证,拒绝非法请求,保护后端的服务,不需要每个服务都做鉴权,在项目中经常有加上OAuth2.0、JWT,Spring Security进行权限校验

2ba3e2ea7dd855b75b6f48add851c3b0.png
  • 压力测试
    有网关的系统,如果要要对某个服务进行压力测试,可以如图所示,改下网关配置既可,测试请求路由到测试服务,测试服务会有单独的测试数据库,这样测试的请求就不会影响到正式的服务和数据库

12531e507eb7f53d845142b5e08d4acd.png

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已经集成

f32f0e6b0ffe6a79cea7993dde701c01.png

2.2 SpringCloud Gateway结构

引用官方图例如图,SpringCloud Gateway的底层基于Netty,主要组成有Predicates(谓词或者断言)、Route(路由)、Filter(过滤器)

7f634db8cb7c62e3a2774b643ea50199.png

画张思维导图表示SpringCloud Gateway的组成:

292eeaeb9436ff69fd6d0930174b6495.png
  • 路由(route):网关的基本构建块。它由ID,目标URI,谓词集合和过滤器集合定义
  • 过滤器(Filter):这些过滤器是使用特定工厂构造的Spring FrameworkGatewayFilter实例
  • 谓词(Predicates): 引用了java8的函数谓词,输入类型是Spring FrameworkServerWebExchange。谓词可以匹配HTTP请求中的所有内容,例如标头或参数

2.3 SpringCloud Gateway工作方式

从总体上概述了Spring Cloud Gateway的工作方式,引用官网的图例:

94bddc30611f59af79579f1cbf0c0d8f.png

从官网的图来看,并不是特别复杂,首先客户端请求都会先经过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

a6b419232abead2f7f021f5278c47b81.png

packaging选择jar,java version选择jdk8的,然后点next

afc85c640c7586f85cc03b028ee05222.png

选择Gateway的依赖,选择之后会自动加上对应pom配置

e508747f0e73a56fb3fce190daa7a7fe.png

Eureka客户端的依赖也可以加上,这样就可以注册服务到eureka服务端

125a95bdcc06137687033e294d0952a7.png

新建项目之后,检查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: true
  instance:
    status-page-url-path: http://localhost:8761/actuator/info
    health-check-url-path: http://localhost:8761/actuator//health
    # 显示ip
    prefer-ip-address: true
    # eureka实例id
    instance-id: api-gateway8082

API Gateway配置:

spring:
  application:
    # 指定application name
    name: api-gateway
  cloud:
    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>
 */
@Configuration
public class GatewayConfiguration {

    @Bean
    public 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

91f26e4f8a28b2b671aa19a53fd695ca.png

5、Gateway谓词工厂分类

SpringCloud Gateway的谓词工厂分类如图,所谓谓词或者说断言,其实就是一种匹配的规则,根据这些匹配,匹配到就经过过滤器

494f4a36c1f71506f4719f83d548fda2.png

SpringCloud Gateway的谓词分类比较多,在SpringCloud官方手册也有进行比较详细的介绍,所以本文章挑几个进行介绍既可

  • After谓词配置

在指定的datetime后触发过滤器

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
            uri: http://127.0.0.1:8083/api/findUser
            predicates:
                - After=2019-01-01T16:30:00+08:00[Asia/Shanghai]
  • Before谓词配置
spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: http://127.0.0.1:8083/api/findUser
          predicates:
            - Before=2018-01-01T16:30:00+08:00[Asia/Shanghai]
  • Between谓词配置
spring:
  cloud:
    gateway:
      routes:
        - id: between_route
          uri: http://127.0.0.1:8083/api/findUser
          predicates:
            - Between=2018-01-01T16:30:00+08:00[Asia/Shanghai], 2019-01-01T16:30:00+08:00[Asia/Shanghai]
  • Cookie谓词配置

加上cookie “chocolate=ch.p” 经过过滤器

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://127.0.0.1:8083/api/findUser
        predicates:
        - Cookie=chocolate, ch.p

linux curl测试接口:

curl http://192.168.9.10:8082/api/findUser?username=nicky --cookie "chocolate=ch.p"

67fe212009e797400ada07ef87e4b0e3.png
  • Header谓词配置

加上请求头参数“X-Request-Id”, d+标识数字

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: http://127.0.0.1:8083/api/findUser
        predicates:
        - 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_route
        uri: http://127.0.0.1:8083/api/findUser
        predicates:
        - 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_route
        uri: http://127.0.0.1:8083/api/findUser
        predicates:
        - 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_route
        uri: http://127.0.0.1:8083/api/findUser
        predicates:
        - Query=username
curl http://192.168.9.30:8082/api/findUser?username=nicky
  • 远程地址谓词

在远程机192.168.1.1调用接口,都会匹配

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://127.0.0.1:8083/api/findUser
        predicates:
        - 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_high
        uri:http://127.0.0.1:8083
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: http://127.0.0.1:8084
        predicates:
        - Weight=group1, 2
curl http://192.168.9.30:8082/api/findUser?username=nicky

6、Gateway过滤器类型分类

45669745e76499a4d90f994b83ae5b7e.png

7、GatewayFilter工厂分类

SpringCloud的gatewayFilter有很多分类,详情参考官方手册,官方手册的介绍也相对比较详细,所以本博客挑几个介绍:

  • PrefixPath GatewayFilter

这个网关过滤器是在请求链接时候加上前缀,如下配置,加上/api的前缀

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: http://127.0.0.1:8083
        filters:
        - 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_route
        uri: http://127.0.0.1:8083
        filters:
        - 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>
 */
@Data
public 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>
 */
@RestController
public class HystrixRestController {

    @GetMapping(value = {"/fallback"})
    public ResultBean fallback() {
        return ResultBean.badRequest("Hystrix fallback");
    }
}

加上配置:

spring:
  cloud:
    gateway:
      routes:
                - id: hystrix_route
          uri: http://127.0.0.1:8083/api/findUser
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: 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:

b7260ff006dc286b94db42d1d959612c.png

781405e0d1201acc010f7bbf7ff46abb.png

所以总的来说,还是要自己配置;

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • Requestratelimiter GatewayFilter

requestratelimiter用于简单的实现限流,基于Redis实现

@Bean
@Primary
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
}

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

KeyResolver需要加上@Primary

006906d1f83b4c3aa4103395a9272170.png
spring:
  redis:
    host: 127.0.0.1
    password:
    port: 6379
  cloud:
    gateway:
      routes:
        ## RequestRateLimiter GatewayFilter简单限流
        - id: requestratelimiter_route
          uri: http://192.168.9.30:8083/api/findUser
          predicates:
            - Method=GET
          filters:
            - name: RequestRateLimiter
              args:
                # 每秒允许处理的请求数量
                redis-rate-limiter.replenishRate: 1
                # 每秒最大处理的请求数量
                redis-rate-limiter.burstCapacity: 2
                #每秒最大处理token数量
                redis-rate-limiter.requestedTokens: 1
                # 限流策略,对应策略的BeanName
                key-resolver: "#{@ipKeyResolver}"

abbb8f25de8ae4363442f70ac558f55e.png
  • Retry GatewayFilter

retry GatewayFilter是用于重试的过滤器

spring:
  cloud:
      gateway:
        routes:
                # RetryFilter 重试过滤器
        - id: retry_test
          uri: http://127.0.0.1:8083/api/findUser
          predicates:
            - Method=GET
          filters:
            - name: Retry
              args:
                retries: 3 # 重试次数
                statuses: BAD_GATEWAY
                methods: GET,POST
                backoff:
                  firstBackoff: 10ms
                  maxBackoff: 50ms
                  factor: 2
                  basedOnPreviousValue: false

f5794ddfef573d9372c6288476889ff1.png

8、GlobalFilter工厂分类介绍

SpringCloud Gateway的GlobalFilter分类如图,详情可以参考官方手册,GlobalFilter是全局的过滤器,作用于所有的路由

8.1 全局过滤器分类

688b07559fc5d12e847a1ef7ea485735.png

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;

@Slf4j
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

配置类进行配置:

@Bean
    public GlobalFilter customFilter() {
        return new CustomGlobalFilter();
    }

009965e68ac2e4b83f9c353fccacd0ec.png

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/html

9.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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值