网关我选 Spring Cloud Gateway

网关可提供请求路由与组合协议转换安全认证服务鉴权流量控制日志监控等服务。可选的网关有很多,好比 Nginx、高性能网关 OpenResty、Linkerd 以及 Spring Cloud Gateway。java

若是是真的追求高性能,那确定是选择 Nginx 或者 OpenResty 无疑了, 可是对性能要求不是很高的话,而且又在用 Spring Cloud 系列,那固然就要选择 Spring Cloud Gateway 了。git

网关的基础就是路由功能,通俗解释就是地址转发,将一个请求地址转发到实际的服务地址。好比请求的是 http://xxx.com/api 的路由地址,实际上会被转发到 http://xxx.com:8888 上来,这就是个最简单的路由方式。github

咱们能够理解为 Spring Cloud Gateway 就是针对进来的请求作各类判断和处理,好比说判断请求的合法性、权限验证,请求地址改写,请求参数、头信息、cookie 信息的分析和改写,请求速率控制,日志留存等。而这些均可以方便的经过 Predicate 和 GatewayFilter 来组合实现。web

建立 Spring Cloud Gateway 项目

Spring Cloud 版本是 Greenwich.SR2,Spring Boot 版本 2.1.6.RELEASE,JDK 1.8。spring

接下来正式建立一个 Gateway 项目。编程

首先作两个微服务,当作路由转发的目标服务api

两个微服务是以 consul 做为服务注册中心的,能够看这篇文章服务注册发现、配置中心集一体的 Spring Cloud Consul安全

一、建立 consul-order 服务,具体能够去 github 上看代码(https://github.com/huzhicheng/spring-cloud-study/tree/master/consul/consul-order),很简单的一个服务。建立的 RESTful Controller 以下:cookie

@RestController
@RequestMapping(value = "order")
public class OrderController {

    @Value("${spring.application.name}")
    private String applicationName;


    @GetMapping(value = "get")
    public CustomerOrder getOrder(){
        CustomerOrder customerOrder = new CustomerOrder();
        customerOrder.setOrderId("9999");
        customerOrder.setProductName("MacBook Pro");
        customerOrder.setClient(applicationName);
        return customerOrder;
    }
}

总之,最后直接访问这个接口的地址为 http://localhost:5006/order/getapp

二、建立 consul-user 服务,具体代码能够到 github 上查看(https://github.com/huzhicheng/spring-cloud-study/tree/master/consul/consul-user)。建立的 RESTful Controller 内容以下:

@RestController
@RequestMapping(value = "user")
public class UserController {

    @GetMapping(value = "get")
    public User getUserInfo(){
        User user = new User();
        user.setName("古时的风筝");
        user.setAge(8);
        user.setLocation("北京");
        return user;
    }
}

和上面的微服务有点区别的就是设置了 context-path

server:
  port: 5005
  servlet:
    context-path: /user-service

之因此这样不一样的设置,是由于下面要验证一个 filter。总之,最后上述接口的访问地址为:http://localhost:5005/user-service/user/get

建立一个项目,并引入 maven 包

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

配置简单的路由转发

路由配置有两种方式。一种是配置文件,另一种是代码方式配置,WebFlux 的反应式编程方式。因此咱们 pom 文件中要引入 WebFlux 的包。这是 Spring 5 的新特性。

一、先看第一种配置文件方式配置:

server:
  port: 10000
spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: false # 是否将服务id转换为小写
      routes:
      - id: userServiceRouter
        uri: lb://consul-user
        predicates:
        - Path=/user-service/**
      - id: orderServiceRouter
        uri: lb://consul-order
        predicates:
        - Path=/order-service/**
        filters:
        - StripPrefix=1
    consul:
      host: localhost #注册gateway网关到consul
      port: 8500
      discovery:
        service-name: service-gateway

其中包括 Spring Boot 项目的基本配置,name、port ,还有关于 consul 的配置,要将网关服务注册到注册中心。

上面配置中建立了两条路由规则,路由规则名称经过 id 设置,分别是 userServiceRouter 和 orderServiceRouter,经过 predicates.Path 设置待转发的 url,经过 uri 设置转发后的目标地址。上面配置将以/user-service/开头的地址转发到 lb://consul-user,固定格式 lb + 服务id,在有注册中心的状况下要这样写,如过没有注册中心,能够直接写目标 url。

下面的路由规则中多了一个 StripPrefix 的 filter ,这个是 Gateway 的内置 filter,做用就是去掉 Path 中的指定部分,StripPrefix=1,就是以 / 分隔,去掉第一部分,好比 /a/b/c 这个地址,在 StripPrefix=1 的做用下,就会转发到 /b/c/,当 StripPrefix=2 的时候,就会转发到 /c/。

配置好上述接口,而后启动网关服务。访问规则就会有以下对应关系:

http://localhost:10000/user-service/user/get->http://localhost:5005/user-service/user/get

http://localhost:10000/order-service/order/get->http://localhost:5006/order/get

固然这只是针对每个目标服务只有一个实例的状况,若是有多个实例,就会按照负载策略落到对应的实例中。

二、代码方式的路由配置

@Bean
public RouteLocator kiteRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("userRouter", r -> r.path("/user-service/**")
            .filters(f ->
                f.addResponseHeader("X-CustomerHeader", "kite"))
            .uri("lb://consul-user")
        )
        .route("orderRouter", r -> r.path("/order-service/**")
            .filters(f -> f.stripPrefix(1)).uri("lb://consul-order")
        )
        .build();
}

上面的这段代码和前面的配置文件的内容是一样的做用。只要实现一个返回类型为 RouteLocator,参数为 RouteLocatorBuilder类型的 Bean。

你看后面那一连串的 r.path().filters().uri() 了吗,用它们就能够简单的配置出路由规则,并且可读性也比较强。另外,Gateway 还套用了 Predicate 的规则来构建更加灵活、复杂的路由规则。Predicate 是 Java 8 增长的逻辑计算库,有 negate()、and()、or()、isEqual()几个方法。具体的代码在 PredicateSpec 和 UriSpec 这两个类里,一目了然。

PredicateSpec 里有这么多方法,均可以结合 and、or 组合起来使用。

接下来就说到 filter,Gateway 内置了不少的 filter,能够在 GatewayFilterSpec 类下找到方法封装,每个 filter 都由一个 factory 的 apply 实现,都在 org.springframework.cloud.gateway.filter.factory包下,有必要的话能够直接看源码。 好比上面用到的 StripPrefix。还有 addResponseHeader,它的做用是在 Response 对象的 header 中添加请求头。

启动网关服务

启动网关,并访问两个接口测试,接口分别为 http://localhost:10000/user-service/user/get和http://localhost:10000/order-service/order/get,正常返回数据,则说明网关服务配置正常。

巧用 StripPrefix filter

微服务多了以后,路由的转发规则也就多了,比方说订单相关请求要转发到订单微服务集群,用户相关请求要转发到用户微服务集群,最终开放给终端的接口也要能代表是哪一个微服务的,除了接口文档里说明以外,接口自己最好也能明确标识。

一种方式是在微服务的配置文件中配置上server.servlet.context-path

还有一种方式就是在路由规则的 path 中配置,而后加上 StripPrefix 配置,选择性的去掉请求 url 中的某些部分。好比咱们请求 Gateway的地址为 order-service/order/get,则通过 StripPrefix(1) 以后,会把请求地址变为 order/get,而后根据路由规则定向到具体的微服务地址或者特定的 url。

本篇就介绍 Spring Cloud Gateway 的基本用法,后续还会有关于集成安全认证、鉴权、限流、日志等相关内容,敬请关注。

不要吝惜你的「推荐」呦

欢迎关注,不按期更新本系列和其余文章
古时的风筝 ,进入公众号能够加入交流群

相关文章
相关标签/搜索