Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。

网关提供API全托管服务,丰富的API管理功能,辅助企业管理大规模的API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等贡呢。一般来说网关对外暴露的URL或者接口信息,我们统称为路由信息。如果研发过网关中间件或者使用过Zuul的人,会知道网关的核心是Filter以及Filter Chain(Filter责任链)。Sprig Cloud Gateway也具有路由和Filter的概念。下面介绍一下Spring Cloud Gateway中几个重要的概念。

  • 路由。路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配

  • 断言。Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息,比如请求头和参数等。

  • 过滤器。一个标准的Spring WebFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理

在这里插入图片描述

Spring Cloud Gateway 接收到请求。然后再由 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到Gateway Web Handler。Handler 再通过指定的过滤器链将请求发送到我们实际的服务执行业务逻辑,然后返回。

之前系统是通过 RouterFunctions 到 Spring Cloud Gateway 实现内部操作。

内部处理快速返回

@Configuration
public class ProcessController {

    @Bean
    public RouterFunction<ServerResponse> globalProcessRoute(GlobalProcessHandler globalProcessHandler) {
        return RouterFunctions.route(POST("/gateway/redirect/fast/finish"), globalProcessHandler::fastFinish);
    }
}

@Component
public class ProcessHandler {

    @NonNull
    public Mono<ServerResponse> fastFinish(ServerRequest request) {
        return ok().body(BodyInserters.fromObject(BizResultDTO.buildSuccess(ReturnCodeEnum.SUCCESS)));
    }

}

下面就是收集用户信息 Filter 组装跳转地址:

CollectUserInfoFilter.java

@Component
public class CollectUserInfoFilter implements GlobalFilter, Ordered {

    private static final Pattern SCHEME_PATTERN = Pattern.compile("[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*");

    private static final String FAST_FINISH_PATH = "/redirect/fast/finish";

    private static final String LOCALHOST = "localhost";

    @Value("${server.port}")
    private String serverPort;

    @Value("${server.context-path}")
    private String appContext;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String bizType = (String) exchange.getAttributes().get(CommonConstants.BIZ_TYPE_KEY);
        if (BizTypeEnum.isFastFinishBizType(bizType)) {
            // 调用内部信息
            exchange = fastFinish(exchange);

            // 收集用户信息

            // 快速返回,不调用业务系统
            return chain.filter(exchange);
        }
        return chain.filter(exchange);

    }

    @Override
    public int getOrder() {
        return 10002;
    }

    private ServerWebExchange fastFinish(ServerWebExchange exchange) {
        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        if (route != null) {
            URI uri = exchange.getRequest().getURI();
            boolean encoded = ServerWebExchangeUtils.containsEncodedParts(uri);
            URI routeUri = route.getUri();
            if (hasAnotherScheme(routeUri)) {
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());
                routeUri = URI.create(routeUri.getSchemeSpecificPart());
            }
            URI mergedUrl = UriComponentsBuilder.fromUri(uri).scheme(routeUri.getScheme()).host(LOCALHOST).port(serverPort)
                    .replacePath(appContext + FAST_FINISH_PATH).build(encoded).toUri();
            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, mergedUrl);
        }
        return exchange;
    }

    private boolean hasAnotherScheme(URI uri) {
        return SCHEME_PATTERN.matcher(uri.getSchemeSpecificPart()).matches() && uri.getHost() == null && uri.getRawPath() == null;
    }

}

下面就是改进后的操作:

public class CollectUserInfoFilter implements GlobalFilter, Ordered {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String bizType = (String) exchange.getAttributes().get(CommonConstants.BIZ_TYPE_KEY);
        if (BizTypeEnum.isFastFinishBizType(bizType)) {
            // 快速返回,不调用业务系统
            return fastFinish(exchange);
        }
        return chain.filter(exchange);

    }

    @Override
    public int getOrder() {
        return 10002;
    }

    private Mono<Void> fastFinish(ServerWebExchange exchange){
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String fastResult = JSON.toJSONString(BizResultDTO.buildSuccess(ReturnCodeEnum.SUCCESS));
        DataBuffer dataBuffer = response.bufferFactory().allocateBuffer().write(fastResult.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(dataBuffer));
    }

}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐