Gateway微服务网关

在SpringCloud微服务架构中,如果前端页面想访问后端服务,一般都是通过API网关实现的。API网关类似于一个反向代理,前端请求会通过网关的路由以负载均衡方式传递给微服务,但API网关通常还需要实现一部分业务逻辑,比如统一的认证鉴权、日志监控、接口缓存等。SpringCloud Gateway能够通过简单的路由配置按规则的实现API路由,它同时也是一个基于Spring WebFlux的Java工程,因此我们很容易通过Java代码对其业务逻辑进行扩展。

同类技术比较

微服务API网关的实现方式有很多,最简单的Nginx/OpenResty其实就可以作为微服务网关;Kong则是基于OpenResty专门设计的一款微服务网关,也是一个很不错的选择;而SpringCloud中,官方给出的解决方案是SpringCloud Gateway;在下一代基于Istio服务网格的微服务架构中,我们不得不优先考虑基于Envoy实现的istio-ingressgateway

上述提到的方案中API网关的基本定位都是类似,只不过实现方式各有不同,在功能完成度上也各有优劣。总的来说,对于Java程序员SpringCloud Gateway是个很好的选择,它性能不错,而且我们很容易通过代码对其业务功能进行扩展。实际开发中,微服务网关的选择其实就见仁见智了,也不一定非要用SpringCloud的方案。

引入Maven依赖

SpringCloud Gateway本质也是一个SpringBoot工程,我们需要创建一个Webflux工程并引入Gateway相关的依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

不过这里我们还要知道,SpringCloud Gateway除了其本身的起步依赖,我们一般还至少需要引入服务发现功能和Actuator,这样API网关才能够通过Consul注册中心注册的服务名找到对应服务,我们根据需要引入即可。

注意:SpringCloud Gateway并不是基于Servlet实现的,而是基于Webflux这套Reactive Web架构实现的,因此和传统Web相关模块不能同时使用,开发时和传统SpringMVC工程也有一些区别。

相关概念

在具体使用SpringCloud Gateway之前,我们还需要了解一些相关概念。

Route:路由,网关最基本的配置单元,由ID、URI、断言和过滤器组成。

Predicate:断言,其实就是决定是否处理一个HTTP处理请求的判断条件,只不过是通过配置的方式实现的,支持通过请求路径、请求头等方式进行配置。

Filter:过滤器,可以对通过API网关的HTTP请求和响应进行统一的拦截和修改。

其实以上概念很像OpenResty,路由和断言就像是Nginx中的location规则,过滤器则可以在OpenResty中使用Lua脚本实现。实际上,API网关大多都是类似的设计。另外要注意,这里所说的Filter与具体的Servlet规范无关,SpringCloud Gateway也不是基于Servlet实现的,这里的Filter是一个抽象的概念,表示请求和响应的拦截组件。

路由配置

SpringCloud Gateway的路由匹配功能非常强大,它支持多种匹配方式,这里我们不会逐一列举演示,下面我们通过一些例子介绍SpringCloud Gateway中的路由基本配置方式。

spring.cloud.gateway.routes[0].id=order
spring.cloud.gateway.routes[0].uri=lb://order
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
  • id:路由ID,指定唯一名字即可,建议使用服务名。
  • uri:反向代理的地址,lb://order表示以负载均衡方式路由到服务中心注册的order服务。
  • predicates:断言,这里Path断言是基于路径和通配符匹配的,这里我们匹配/**,其实就是所有路径都匹配,除了Path还有很多其它判断方式,比如基于Header等,具体可以参考文档。断言支持配置多个,它们是AND关系。

在SpringCloud微服务工程中,uri我们一般写lb://格式的服务名,不过实际上该处配置也支持直接写明类似Nginx中proxy_pass配置的主机和端口,例子如下,这种方式实际上就相当于固定访问一个主机的端口,通常用于非注册中心管理的其它服务。

spring.cloud.gateway.routes[0].uri=http://127.0.0.1:8081

Filter过滤器

过滤器能够对请求和响应信息进行修改,因此主要分为前置和后置两种类型,下面介绍一些常用的Filter。

PrefixPath 前缀路径过滤器

PrefixPath过滤器能够对请求路径拼上特定的前缀,下面配置中,/**会被拼为/api/**

spring.cloud.gateway.routes[0].id=order_queryOrderById
spring.cloud.gateway.routes[0].uri=lb://order
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
spring.cloud.gateway.routes[0].filters[0]=PrefixPath=/api

RewritePath 重写过滤器

Nginx中重写(Rewrite)功能是很强大的,Spring Cloud Gateway很容易实现基于正则表达式重写。下面配置中,我们使用RewritePath过滤器将/sss/**重写为了/api/**

spring.cloud.gateway.routes[0].id=order_queryOrderById
spring.cloud.gateway.routes[0].uri=lb://order
spring.cloud.gateway.routes[0].predicates[0]=Path=/sss/**
spring.cloud.gateway.routes[0].filters[0]=RewritePath=/sss/?(?<segment>.*),/api/$\{segment}

自定义全局过滤器

上面过滤器都是SpringCloud Gateway内置的过滤器,实际上SpringCloud Gateway也支持自定义全局过滤器。实际开发中,我们可以自定义全局过滤器实现接口认证、鉴权、限流等功能,下面是一个全局过滤器的例子。

package com.gacfox.demo.gateway.filter;

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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class GatewayGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("前置处理...");
        Mono<Void> result = chain.filter(exchange);
        log.info("后置处理...");
        return result;
    }

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

上面代码我们实现了一个全局过滤器,代码比较简单,这里就不多介绍了。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap