SpringCloud Gateway使用redis实现动态路由

1. 将 actuator 端点暴露出来

 
  1. management:

  2. endpoints:

  3. web:

  4. exposure:

  5. include: "*"

2. redis 配置

https://www.cnblogs.com/idea360/p/12632801.html

3. 将原内存路由持久化到 redis

 
  1. @Component

  2. public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {

  3.  
  4. /**

  5. * hash存储的key

  6. */

  7. public static final String GATEWAY_ROUTES = "gateway_dynamic_route";

  8.  
  9. @Resource

  10. private StringRedisTemplate redisTemplate;

  11.  
  12. /**

  13. * 获取路由信息

  14. * @return

  15. */

  16. @Override

  17. public Flux getRouteDefinitions() {

  18. List routeDefinitions = new ArrayList<>();

  19. redisTemplate.opsForHash().values(GATEWAY_ROUTES).stream()

  20. .forEach(routeDefinition -> routeDefinitions.add(JSON.parseObject(routeDefinition.toString(), RouteDefinition.class)));

  21. return Flux.fromIterable(routeDefinitions);

  22. }

  23.  
  24. @Override

  25. public Mono save(Mono route) {

  26. return route.flatMap(routeDefinition -> {

  27. redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(), JSONObject.toJSONString(routeDefinition));

  28. return Mono.empty();

  29. });

  30. }

  31.  
  32. @Override

  33. public Mono delete(Mono routeId) {

  34. return routeId.flatMap(id -> {

  35. if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTES, id)) {

  36. redisTemplate.opsForHash().delete(GATEWAY_ROUTES, id);

  37. return Mono.empty();

  38. }

  39. return Mono.defer(() -> Mono.error(new NotFoundException("route definition is not found, routeId:" + routeId)));

  40. });

  41. }

  42.  
  43. }

4. 重写动态路由服务

 
  1. @Service

  2. public class GatewayDynamicRouteService implements ApplicationEventPublisherAware {

  3.  
  4. @Resource

  5. private RedisRouteDefinitionRepository redisRouteDefinitionRepository;

  6.  
  7. private ApplicationEventPublisher applicationEventPublisher;

  8.  
  9. /**

  10. * 增加路由

  11. * @param routeDefinition

  12. * @return

  13. */

  14. public int add(RouteDefinition routeDefinition) {

  15. redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();

  16. applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));

  17. return 1;

  18. }

  19.  
  20. /**

  21. * 更新

  22. * @param routeDefinition

  23. * @return

  24. */

  25. public int update(RouteDefinition routeDefinition) {

  26. redisRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId()));

  27. redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();

  28. applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));

  29. return 1;

  30. }

  31.  
  32. /**

  33. * 删除

  34. * @param id

  35. * @return

  36. */

  37. public Mono> delete(String id) {

  38. return redisRouteDefinitionRepository.delete(Mono.just(id)).then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))

  39. .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()));

  40. }

  41.  
  42.  
  43. @Override

  44. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

  45. this.applicationEventPublisher = applicationEventPublisher;

  46. }

  47. }

5. 对外暴露接口

 
  1. @RestController

  2. @RequestMapping("/gateway")

  3. public class GatewayDynamicRouteController {

  4.  
  5. @Resource

  6. private GatewayDynamicRouteService gatewayDynamicRouteService;

  7.  
  8. @PostMapping("/add")

  9. public String create(@RequestBody RouteDefinition entity) {

  10. int result = gatewayDynamicRouteService.add(entity);

  11. return String.valueOf(result);

  12. }

  13.  
  14. @PostMapping("/update")

  15. public String update(@RequestBody RouteDefinition entity) {

  16. int result = gatewayDynamicRouteService.update(entity);

  17. return String.valueOf(result);

  18. }

  19.  
  20. @DeleteMapping("/delete/{id}")

  21. public Mono> delete(@PathVariable String id) {

  22. return gatewayDynamicRouteService.delete(id);

  23. }

  24.  
  25. }

测试

测试前删除我们配置的静态路由,因为静态路由和 redis 动态路由同时存在时取并集。

  1. 访问 http://localhost:2000/actuator/gateway/routes , 可以看到只有默认路由。
 
  1. [

  2. {

  3. "route_id": "CompositeDiscoveryClient_consul",

  4. "route_definition": {

  5. "id": "CompositeDiscoveryClient_consul",

  6. "predicates": [

  7. {

  8. "name": "Path",

  9. "args": {

  10. "pattern": "/consul/**"

  11. }

  12. }

  13. ],

  14. "filters": [

  15. {

  16. "name": "RewritePath",

  17. "args": {

  18. "regexp": "/consul/(?.*)",

  19. "replacement": "/${remaining}"

  20. }

  21. }

  22. ],

  23. "uri": "lb://consul",

  24. "order": 0

  25. },

  26. "order": 0

  27. },

  28. {

  29. "route_id": "CompositeDiscoveryClient_idc-gateway",

  30. "route_definition": {

  31. "id": "CompositeDiscoveryClient_idc-gateway",

  32. "predicates": [

  33. {

  34. "name": "Path",

  35. "args": {

  36. "pattern": "/idc-gateway/**"

  37. }

  38. }

  39. ],

  40. "filters": [

  41. {

  42. "name": "RewritePath",

  43. "args": {

  44. "regexp": "/idc-gateway/(?.*)",

  45. "replacement": "/${remaining}"

  46. }

  47. }

  48. ],

  49. "uri": "lb://idc-gateway",

  50. "order": 0

  51. },

  52. "order": 0

  53. },

  54. {

  55. "route_id": "CompositeDiscoveryClient_idc-provider1",

  56. "route_definition": {

  57. "id": "CompositeDiscoveryClient_idc-provider1",

  58. "predicates": [

  59. {

  60. "name": "Path",

  61. "args": {

  62. "pattern": "/idc-provider1/**"

  63. }

  64. }

  65. ],

  66. "filters": [

  67. {

  68. "name": "RewritePath",

  69. "args": {

  70. "regexp": "/idc-provider1/(?.*)",

  71. "replacement": "/${remaining}"

  72. }

  73. }

  74. ],

  75. "uri": "lb://idc-provider1",

  76. "order": 0

  77. },

  78. "order": 0

  79. },

  80. {

  81. "route_id": "CompositeDiscoveryClient_idc-provider2",

  82. "route_definition": {

  83. "id": "CompositeDiscoveryClient_idc-provider2",

  84. "predicates": [

  85. {

  86. "name": "Path",

  87. "args": {

  88. "pattern": "/idc-provider2/**"

  89. }

  90. }

  91. ],

  92. "filters": [

  93. {

  94. "name": "RewritePath",

  95. "args": {

  96. "regexp": "/idc-provider2/(?.*)",

  97. "replacement": "/${remaining}"

  98. }

  99. }

  100. ],

  101. "uri": "lb://idc-provider2",

  102. "order": 0

  103. },

  104. "order": 0

  105. }

  106. ]

这个时候访问 http://192.168.124.5:2000/idc-provider1/provider1/1 根据结果可以推测能正确路由到 provider1, 测试结果一致。

  1. 创建 provider1 路由,将路径设置为 /p1/**,测试是否生效。

POST 请求 http://localhost:2000/gateway/add

 
  1. {

  2. "id":"provider1",

  3. "predicates":[

  4. {

  5. "name":"Path",

  6. "args":{

  7. "_genkey_0":"/p1/**"

  8. }

  9. },

  10. {

  11. "name":"RemoteAddr",

  12. "args":{

  13. "_genkey_0":"192.168.124.5/16"

  14. }

  15. }

  16. ],

  17. "filters":[

  18. {

  19. "name":"StripPrefix",

  20. "args":{

  21. "_genkey_0":"1"

  22. }

  23. }

  24. ],

  25. "uri":"lb://idc-provider1",

  26. "order":0

  27. }

查看 redis 存储,或者请求 http://localhost:2000/actuator/gateway/routes , 都可以看到配置成功。

你可能感兴趣的:(gateway,网关,gateway)