基于spring cloud gateway+sentinel构建微服务网关

基于spring cloud gateway+sentinel构建微服务网关

前言

本文代码于GitHub - felixlyd/gateway-sentinel-sample: spring cloud gateway+sentinel+数据安全处理

spring cloud alibaba对应boot、cloud版本

Spring Cloud Gateway微服务网关教程

Spring Cloud Gateway-官网介绍

  • spring cloud gateway实现API发布、路由转发
  • 引入sentinel实现限流和熔断;引入sentinel-dashboard实现限流监控
  • 考虑接口安全设计:密文、防重放、签名和验签
  • 全局异常处理
  • 日志配置
  • 自动部署
  • actuator健康检查
  • 打印日志?打哪些?请求和响应内容打不打?
  • 占用哪些端口?sentinel-dashboard和sentinel-client
  • sentinel-dashboard部署在哪台机器?

坑指南

无法添加自定义API分组

现象:

经过反复验证测试,spring cloud gateway+sentinel搭建微服务网关时,硬编码配置限流规则时,无法配置自定义API分组Set<ApiDefinition> 加载到GatewayApiDefinitionManager中。如果有相关硬编码,则启动时无法被sentinel dashboard识别,但限流规则仍然生效。而zuul+sentinel搭建微服务网关,硬编码配置限流规则可以配置自定义API分组。

原因:

尚不明确,可能是sentinel的bug。

测试过程:

  1. 硬编码限流规则,添加自定义API分组,启动sentinel dashboard,分别启动zuul和gateway,发现gateway不被识别,zuul被识别;2. 硬编码限流规则,去掉自定义API分组,启动sentinel dashboard,分别启动zuul和gateway,两者均被识别。3. 继续测试其他限流规则硬编码的影响,例如普通限流规则、热点限流规则、熔断降级规则、系统规则,均不会造成sentinel dashboard不识别网关应用的现象。

解决办法:

**虽然sentinel+gateway无法通过代码硬编码配置自定义API分组,但gateway本身可以在路由配置中,将API分组为不同的路由,因此可以替代sentinel的自定义API分组。**后续如果进行规则持久化到DB的优化,有可能解决这一问题。

sentinel指定目录失效

修改spring.cloud.sentinel.log.dir,不起作用,还是会到默认的~/logs/csp路径来。 经过测试,2.6.11不生效,2.6.3版本生效

2021.0.4.0* Spring Cloud 2021.0.4 2.6.11
2021.0.1.0 Spring Cloud 2021.0.1 2.6.3

请求流重复获取

参考

自定义过滤器 Spring Cloud Gateway—自定义过滤器 - 掘金

Spring Cloud Gateway 4 自定义Filter - 路迢迢 - 博客园

请求流重复获取的一些实现,但可能有问题?

Gateway网关自定义拦截器的不可重复读取数据_databufferutils.join_飘零未归人的博客-CSDN博客 SpringCloud Gateway自定义filter获取body中的数据为空_mameng1998的博客-CSDN博客

SpringCloud Gateway读取Request Body方式 - 掘金

Spring Cloud Gateway(读取、修改 Request Body) - 掘金

讲了几种请求流重复获取方案的缺陷:Spring Cloud Gateway 之获取请求体(Request Body)的几种方式 - 码农的进击 - 博客园

请求流获取和修改的官网API: Spring Cloud Gateway 结合官网API的实现: ModifyRequestBodyGatewayFilterFactory获取并修改请求体_GavinYCF的博客-CSDN博客

gateway 网关过滤器之修改body内容

Spring cloud gateway中的request是基于Web Flux,和普通的请求方式不同,不能直接按照普通的ServletRequest去处理请求数据,而是一个reactive.ServletRequest

代码

如果使用官网API的ModifyRequestBodyGatewayFilterFactory去修改请求数据,那么整个路由配置无法放在配置文件application.yml中,因为官网API需要一个RewriteFunction,在配置文件中只能写类名,类名是String,无法转换为RewriteFunction。官网API也声明了该过滤器只能通过Java代码实现。

代码实现

package com.bocd.mkt.gatewaysentinelsample.config;

import com.bocd.mkt.gatewaysentinelsample.filter.SecurityRequestFilter;
import org.springframework.beans.factory.annotation.Autowired;
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;
import org.springframework.http.MediaType;

@Configuration
public class GatewayRoutesConfig {

    @Autowired
    private SecurityRequestFilter securityRequestFilter;

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder){

        return builder.routes().route("test", r -> r
                        .path("/api-a/**")
                        .filters(f -> f
                                .modifyRequestBody(String.class,String.class, MediaType.APPLICATION_JSON_VALUE, securityRequestFilter))
                        .uri("lb://RULE-LITEFLOW")
        ).build();
    }
}

配置信息

解决方式1

继承ModifyRequestBodyGatewayFilterFactory,重写其配置,将其配置信息改为字符串类型,然后在实现方法中根据RewriteFunction类名去反射调用spring容器中的RewriteFunction

方式1可能有潜在问题,不然为啥gateway官方不这样做?

解决方式2

按照ModifyRequestBodyGatewayFilterFactory的实现方式,简化其配置,在原方法中,为了能兼容大多数情况,该类需要传入一个输入类名、输出类名、请求的content-type和一个重写方法RewriteFunction,实际上,我们不需要这么多参数和步骤。

解决方式3

按照官网API建议,将路由配置写在代码中。

全局异常处理

参考

全局异常处理 Spring Cloud Gateway-自定义异常处理 - duanxz - 博客园

【SpringCloud】Spring Cloud Gateway 网关全局异常处理_springcloudgateway全局异常处理_islin_7的博客-CSDN博客

优雅的自定义Spring Cloud Gateway全局异常处理

sentinel的 api-gateway-flow-control | Sentinel

Gateway结合Sentinel1.8限流熔断管理以及自定义异常

SpringCloud: gateway整合sentinel 自定义异常处理类_amadeus_liu2的博客-CSDN博客

sentinel接入网关 自定义异常

端点应用监控

参考

Spring Boot 2.x系列【20】应用监控篇之Actuator入门案例及端点配置详解_management.endpoints_云烟成雨TD的博客-CSDN博客

性能测试

加密解密

jmeter加密解密(加密篇)

打印日志

Spring Cloud Gateway, logging request/response

SpringCloudGateway - Log incoming request url and corresponding route URI

责任链

spring 设计模式中的责任链怎么实现? - 知乎