内容简介:功能:希望外部訪問並且將路由資訊儲存至 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 上有哪些服務
跟 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 查一下
接下來去請求 ACC-V1 的資料
curl -X GET http://localhost:9000/ACC/V1/version
ResponseBody
{
"appName": "acc-v1"
}
可以正確拿到v1的資料
此時啟動新的服務版本是 v2
這時候去拿 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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java Servlet & JSP Cookbook
Bruce W. Perry / O'Reilly Media / 2003-12-1 / USD 49.99
With literally hundreds of examples and thousands of lines of code, the Java Servlet and JSP Cookbook yields tips and techniques that any Java web developer who uses JavaServer Pages or servlets will ......一起来看看 《Java Servlet & JSP Cookbook》 这本书的介绍吧!