客製 Spring Cloud Gateway 路由表 並儲存至 Redis

栏目: Java · 发布时间: 7年前

内容简介:功能:希望外部訪問並且將路由資訊儲存至 Redis 下次重啟 or 增加新的 gateway 不用重新配置路由資訊.

功能:

希望外部訪問 http://domain/acc/v1/endpoint 時, 可以轉發到 springcloud 中 ACC-V1 的實例,

並且將路由資訊儲存至 Redis 下次重啟 or 增加新的 gateway 不用重新配置路由資訊.

配置部分

application.yml

spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false
  redis:
    host: 127.0.0.1
    port: 6379
    password:
server:
  port: ${port:9000}
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    prefer-ip-address: true
management:
  endpoints:
    web:
      exposure:
        include: '*'

關閉由服務發現來建立路由

spring.cloud.gateway.discovery.locator.enabled = false

開放 gateway 的 endpoint

management.endpoints.web.exposure.include = "*"

程式部分

準備兩支

Redis 配置

RedisConfig.java

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

需要配置使用 Json 儲存到 Redis, 因為 org.springframework.cloud.gateway.route.RouteDefinition 並沒有 implements Serializable,

所以不轉成 Json 會出錯.

實作 RouteDefinitionRepository

RedisRouteDefinitionRepository.java

@Slf4j
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
    public static final String GATEWAY_ROUTES = "geteway_routes";

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        redisTemplate.opsForHash().values(GATEWAY_ROUTES).stream().forEach(routeDefinition -> {
            try {
                routeDefinitions.add((RouteDefinition) routeDefinition);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route
                .flatMap(routeDefinition -> {
                    redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(),
                            routeDefinition);
                    return Mono.empty();
                });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTES, id)) {
                redisTemplate.opsForHash().delete(GATEWAY_ROUTES, id);
                return Mono.empty();
            }
            return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: " + routeId)));
        });
    }
}

gateway 預設是將路由放在記憶體中管理, 但當發現有額外提供 RouteDefinitionRepository 時則會採用你提供的,

這邊實作則是將路由寫到 Redis 做存放.

看一下 Eureka 上有哪些服務

客製 Spring Cloud Gateway 路由表 並儲存至 Redis

跟 gateway 要路由表資訊看看

curl -X GET http://localhost:9000/actuator/gateway/routes

ResponseBody

[]

可以看到路由表是空的

新增路由

curl -X POST \
  http://localhost:9000/actuator/gateway/routes/acc_v1 \
  -H 'Content-Type: application/json' \
  -d '{
  "predicates": [
    {
      "name": "Path",
      "args": {
        "pattern": "/ACC/V1/**"
      }
    }
  ],
  "filters": [
    {
      "name": "RewritePath",
      "args": {
        "regexp": "/ACC/V1/(?<remaining>.*)",
        "replacement": "/${remaining}"
      }
    }
  ],
  "uri": "lb://ACC-V1",
  "order": 0
}'

再次做查詢

curl -X GET http://localhost:9000/actuator/gateway/routes

ResponseBody

[
    {
        "route_id": "acc_v1",
        "route_definition": {
            "id": "acc_v1",
            "predicates": [
                {
                    "name": "Path",
                    "args": {
                        "pattern": "/ACC/V1/**"
                    }
                }
            ],
            "filters": [
                {
                    "name": "RewritePath",
                    "args": {
                        "regexp": "/ACC/V1/(?<remaining>.*)",
                        "replacement": "/${remaining}"
                    }
                }
            ],
            "uri": "lb://ACC-V1",
            "order": 0
        },
        "order": 0
    }
]

此時可以發現已經有路由表了, 也去 Redis 查一下

客製 Spring Cloud Gateway 路由表 並儲存至 Redis

接下來去請求 ACC-V1 的資料

curl -X GET http://localhost:9000/ACC/V1/version

ResponseBody

{
    "appName": "acc-v1"
}

可以正確拿到v1的資料

此時啟動新的服務版本是 v2

客製 Spring Cloud Gateway 路由表 並儲存至 Redis

這時候去拿 v2 資料是拿不到

curl -X GET http://localhost:9000/ACC/V2/version

ResponseBody

{
    "timestamp": "2018-11-07T09:11:10.323+0000",
    "path": "/ACC/V2/version",
    "status": 404,
    "error": "Not Found",
    "message": null
}

增加新服務路由 v2

curl -X POST \
  http://localhost:9000/actuator/gateway/routes/acc_v2 \
  -H 'Content-Type: application/json' 
  -d '{
  "predicates": [
    {
      "name": "Path",
      "args": {
        "pattern": "/ACC/V2/**"
      }
    }
  ],
  "filters": [
    {
      "name": "RewritePath",
      "args": {
        "regexp": "/ACC/V2/(?<remaining>.*)",
        "replacement": "/${remaining}"
      }
    }
  ],
  "uri": "lb://ACC-V2",
    "order": 0
}'

這時候去拿 v2 的資料就可以正確取得

curl -X GET http://localhost:9000/ACC/V2/version

ResponseBody

{
    "appName": "acc-v2"
}

但服務 acc-v1 還是可以訪問到, v1 v2 服務同時提供服務, 並且透過 url 來指定就完成了

curl -X GET http://localhost:9000/ACC/V1/version

ResponseBody

{
    "appName": "acc-v1"
}

當 v1 要廢棄的時候, 可以先透過 management.endpoints 來刪除

curl -X DELETE \
  http://localhost:9000/actuator/gateway/routes/acc_v1

刪除之後確定沒問題就可以真正的把服務關掉囉

curl -X GET \
  http://localhost:9000/actuator/gateway/routes

ResponseBody

[
    {
        "route_id": "acc_v2",
        "route_definition": {
            "id": "acc_v2",
            "predicates": [
                {
                    "name": "Path",
                    "args": {
                        "pattern": "/ACC/V2/**"
                    }
                }
            ],
            "filters": [
                {
                    "name": "RewritePath",
                    "args": {
                        "regexp": "/ACC/V2/(?<remaining>.*)",
                        "replacement": "/${remaining}"
                    }
                }
            ],
            "uri": "lb://ACC-V2",
            "order": 0
        },
        "order": 0
    }
]

當 gateway 重啟或是增加新的時候, 都會去 Redis 取得路由資訊, 這樣就不用一個一個去配置啦

如果手動增加或刪除 Redis 內的路由資訊, 其實也是可以同步到所有 Gateway 上, 這樣也不一定需要開 management.endpoints gateway.


以上所述就是小编给大家介绍的《客製 Spring Cloud Gateway 路由表 並儲存至 Redis》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A Philosophy of Software Design

A Philosophy of Software Design

John Ousterhout / Yaknyam Press / 2018-4-6 / GBP 14.21

This book addresses the topic of software design: how to decompose complex software systems into modules (such as classes and methods) that can be implemented relatively independently. The book first ......一起来看看 《A Philosophy of Software Design》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码