当前位置:   article > 正文

Spring Cloud Gateway 集成 Sentinel(二)实现nacos动态保存配置_rule-type: gw-flow

rule-type: gw-flow

按照 (一)部署完成之后

一、改造网关

1. 在网关项目pom文件中新增 持久化依赖

  1. <!-- Sentinel 持久化配置,支持多种持久化数据源:file、nacos、zookeeper、apollo、redis、consul 非必须,按需选择,这里使用的是 nacos-->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. </dependency>

2. 修改网关yaml配置

新增spring.cloud.sentinel.datasource

其中api代表的为数据源名字,可自主起名,server-addr 为 nacos主机连接ip与端口,可通过${spring.cloud.nacos.config.server-addr} 从注册中心获取

rule-type的配置项对应RuleType 枚举类。

public enum RuleType {
    FLOW("flow", FlowRule.class),
    DEGRADE("degrade", DegradeRule.class),
    PARAM_FLOW("param-flow", ParamFlowRule.class),
    SYSTEM("system", SystemRule.class),
    AUTHORITY("authority", AuthorityRule.class),
    GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
    GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
}

  1. spring:
  2. cloud:
  3. sentinel:
  4. enable: true
  5. filter:
  6. enabled: false
  7. eager: true #立即加载
  8. transport:
  9. port: 9010
  10. dashboard: 127.0.0.1:8080
  11. # dashboard: 172.16.10.233:9010
  12. scg:
  13. # 限流后的相应配置
  14. fallback:
  15. content-type: application/json
  16. # 模式: response / redirect
  17. mode: response
  18. # 相应状态码
  19. response-status: 200
  20. # 相应消息体
  21. response-body: '{"code":0,"message":"服务忙请稍后再试...","data":null}'
  22. # Sentinel 流控规则持久化
  23. datasource:
  24. api:
  25. nacos:
  26. server-addr: 127.0.0.1:8848
  27. namespace: ****************
  28. # 组名 默认 DEFAULT_GROUP
  29. group-id: 'SENTINEL_GROUP'
  30. # Nacos 中配置的Id
  31. data-id: ${spring.application.name}-api-rules
  32. # RuleType
  33. rule-type: gw-api-group
  34. # 默认就是Json
  35. data-type: 'json'
  36. # 自定义命名
  37. flow:
  38. # 支持多种持久化数据源:file、nacos、zookeeper、apollo、redis、consul
  39. nacos:
  40. # 配置类com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties
  41. # 连接地址
  42. server-addr: 127.0.0.1:8848
  43. namespace: ****************
  44. # 组名 默认 DEFAULT_GROUP
  45. group-id: 'SENTINEL_GROUP'
  46. # Nacos 中配置的Id
  47. data-id: ${spring.application.name}-flow-rules
  48. # RuleType
  49. rule-type: gw-flow
  50. # 默认就是Json
  51. data-type: 'json'

 二、改造sentinel-dashboard

1.修改pom 

  1. <!-- for Nacos rule publisher sample -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. <scope>test</scope>
  6. </dependency>

  1. <!-- for Nacos rule publisher sample -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. </dependency>

2.修改 application.properties 新增

  1. # local
  2. spring.cloud.sentinel.datasource.ds.nacos.serverAddr = 127.0.0.1 #nacos地址
  3. spring.cloud.sentinel.datasource.ds.nacos.groupId=SENTINEL_GROUP
  4. spring.cloud.sentinel.datasource.ds.nacos.namespace=***** #nacos对应的 namespace

3. 修改代码

1) 将test文件夹下 

com.alibaba.csp.sentinel.dashboard.rule.nacos 拷贝到com.alibaba.csp.sentinel.dashboard.controller.gateway下

并修改 NacosConfig

  1. @Configuration
  2. public class NacosConfig {
  3. @Value("${spring.cloud.sentinel.datasource.ds.nacos.serverAddr}")
  4. private String serverAddr;
  5. @Value("${spring.cloud.sentinel.datasource.ds.nacos.namespace}")
  6. private String namespace;
  7. @Bean
  8. public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
  9. return JSON::toJSONString;
  10. }
  11. @Bean
  12. public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
  13. return s -> JSON.parseArray(s, FlowRuleEntity.class);
  14. }
  15. @Bean
  16. public ConfigService nacosConfigService() throws Exception {
  17. Properties properties = new Properties();
  18. properties.setProperty(PropertyKeyConst.SERVER_ADDR,serverAddr);
  19. properties.setProperty(PropertyKeyConst.NAMESPACE,namespace);
  20. return ConfigFactory.createConfigService(properties);
  21. }
  22. @Bean
  23. public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() {
  24. return JSON::toJSONString;
  25. }
  26. @Bean
  27. public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() {
  28. return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class);
  29. }
  30. @Bean
  31. public Converter<List<ApiDefinitionEntity>, String> gatewayApiEntityEncoder() {
  32. return JSON::toJSONString;
  33. }
  34. @Bean
  35. public Converter<String, List<ApiDefinitionEntity>> gatewayApiEntityDecoder() {
  36. return s -> JSON.parseArray(s, ApiDefinitionEntity.class);
  37. }
  38. }

2) 新增 nacos api的数据提供类 用于在nacos 发布 和 获取规则

GatewayFlowRuleNacosProvider
  1. @Component("gatewayFlowRuleNacosProvider")
  2. public class GatewayFlowRuleNacosProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> {
  3. @Autowired
  4. private ConfigService configService;
  5. // 规则对象的转换器,获取到的数据根据使用的数据类型的不同,需要用不同的转换器转化后使用
  6. @Autowired
  7. private Converter<String, List<GatewayFlowRuleEntity>> converter;
  8. @Override
  9. public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception {
  10. String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
  11. NacosConfigUtil.GROUP_ID, 3000);
  12. if (StringUtil.isEmpty(rules)) {
  13. return new ArrayList<>(0);
  14. }
  15. return converter.convert(rules);
  16. }
  17. }
GatewayFlowRuleNacosPublisher
  1. @Component("gatewayFlowRuleNacosPublisher")
  2. public class GatewayFlowRuleNacosPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> {
  3. // 数据源的配置服务
  4. @Autowired
  5. private ConfigService configService;
  6. /**
  7. * <p>数据通信的转换器。
  8. * <p>在config包下的NacosConfig类中声明的Spring Bean对象。
  9. * <p>负责将实体对象转换为json格式的字符串</p>
  10. */
  11. @Autowired
  12. private Converter<List<GatewayFlowRuleEntity>, String> converter;
  13. @Override
  14. public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception {
  15. AssertUtil.notEmpty(app, "app name cannot be empty");
  16. if (rules == null) {
  17. return;
  18. }
  19. /*
  20. * 将规则发布到动态数据源作持久化,第一个参数是app+后缀,此处用的是-flow-rules的后缀;
  21. * 第二个参数是nacos分组id,这个用默认提供的sentinel预留项即可;最后一个参数是数据转换
  22. * 器,要将对象转换成统一的格式后,网络传输到nacos。
  23. */
  24. configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
  25. NacosConfigUtil.GROUP_ID, converter.convert(rules));
  26. }
  27. }

3.) 对照着  GatewayFlowRuleController 新增 GatewayFlowRuleControllerV2

并 修改数据的获取方式 原先为通过  sentinelApiClient 获取 修改为通过 上面创建的 发布和获取类获取

  1. @RestController
  2. @RequestMapping(value = "/v2/gateway/flow")
  3. public class GatewayFlowRuleControllerV2 {
  4. private final Logger logger = LoggerFactory.getLogger(GatewayFlowRuleController.class);
  5. @Autowired
  6. private InMemGatewayFlowRuleStore repository;
  7. @Autowired
  8. @Qualifier("gatewayFlowRuleNacosProvider")
  9. private DynamicRuleProvider<List<GatewayFlowRuleEntity>> ruleProvider;
  10. @Autowired
  11. @Qualifier("gatewayFlowRuleNacosPublisher")
  12. private DynamicRulePublisher<List<GatewayFlowRuleEntity>> rulePublisher;
  13. @Autowired
  14. private AuthService<HttpServletRequest> authService;
  15. @GetMapping("/list.json")
  16. public Result<List<GatewayFlowRuleEntity>> queryFlowRules(HttpServletRequest request, String app, String ip, Integer port) {
  17. AuthService.AuthUser authUser = authService.getAuthUser(request);
  18. authUser.authTarget(app, AuthService.PrivilegeType.READ_RULE);
  19. if (StringUtil.isEmpty(app)) {
  20. return Result.ofFail(-1, "app can't be null or empty");
  21. }
  22. if (StringUtil.isEmpty(ip)) {
  23. return Result.ofFail(-1, "ip can't be null or empty");
  24. }
  25. if (port == null) {
  26. return Result.ofFail(-1, "port can't be null");
  27. }
  28. try {
  29. List<GatewayFlowRuleEntity> rules = ruleProvider.getRules(app);
  30. repository.saveAll(rules);
  31. return Result.ofSuccess(rules);
  32. } catch (Throwable throwable) {
  33. logger.error("query gateway flow rules error:", throwable);
  34. return Result.ofThrowable(-1, throwable);
  35. }
  36. }
  37. @PostMapping("/new.json")
  38. public Result<GatewayFlowRuleEntity> addFlowRule(HttpServletRequest request, @RequestBody AddFlowRuleReqVo reqVo) {
  39. AuthService.AuthUser authUser = authService.getAuthUser(request);
  40. String app = reqVo.getApp();
  41. if (StringUtil.isBlank(app)) {
  42. return Result.ofFail(-1, "app can't be null or empty");
  43. }
  44. authUser.authTarget(app, AuthService.PrivilegeType.WRITE_RULE);
  45. GatewayFlowRuleEntity entity = new GatewayFlowRuleEntity();
  46. entity.setApp(app.trim());
  47. String ip = reqVo.getIp();
  48. if (StringUtil.isBlank(ip)) {
  49. return Result.ofFail(-1, "ip can't be null or empty");
  50. }
  51. entity.setIp(ip.trim());
  52. Integer port = reqVo.getPort();
  53. if (port == null) {
  54. return Result.ofFail(-1, "port can't be null");
  55. }
  56. entity.setPort(port);
  57. // API类型, Route ID或API分组
  58. Integer resourceMode = reqVo.getResourceMode();
  59. if (resourceMode == null) {
  60. return Result.ofFail(-1, "resourceMode can't be null");
  61. }
  62. if (!Arrays.asList(RESOURCE_MODE_ROUTE_ID, RESOURCE_MODE_CUSTOM_API_NAME).contains(resourceMode)) {
  63. return Result.ofFail(-1, "invalid resourceMode: " + resourceMode);
  64. }
  65. entity.setResourceMode(resourceMode);
  66. // API名称
  67. String resource = reqVo.getResource();
  68. if (StringUtil.isBlank(resource)) {
  69. return Result.ofFail(-1, "resource can't be null or empty");
  70. }
  71. entity.setResource(resource.trim());
  72. // 针对请求属性
  73. GatewayParamFlowItemVo paramItem = reqVo.getParamItem();
  74. if (paramItem != null) {
  75. GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();
  76. entity.setParamItem(itemEntity);
  77. // 参数属性 0-ClientIP 1-Remote Host 2-Header 3-URL参数 4-Cookie
  78. Integer parseStrategy = paramItem.getParseStrategy();
  79. if (!Arrays.asList(PARAM_PARSE_STRATEGY_CLIENT_IP, PARAM_PARSE_STRATEGY_HOST, PARAM_PARSE_STRATEGY_HEADER
  80. , PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
  81. return Result.ofFail(-1, "invalid parseStrategy: " + parseStrategy);
  82. }
  83. itemEntity.setParseStrategy(paramItem.getParseStrategy());
  84. // 当参数属性为2-Header 3-URL参数 4-Cookie时,参数名称必填
  85. if (Arrays.asList(PARAM_PARSE_STRATEGY_HEADER, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
  86. // 参数名称
  87. String fieldName = paramItem.getFieldName();
  88. if (StringUtil.isBlank(fieldName)) {
  89. return Result.ofFail(-1, "fieldName can't be null or empty");
  90. }
  91. itemEntity.setFieldName(paramItem.getFieldName());
  92. String pattern = paramItem.getPattern();
  93. // 如果匹配串不为空,验证匹配模式
  94. if (StringUtil.isNotEmpty(pattern)) {
  95. itemEntity.setPattern(pattern);
  96. Integer matchStrategy = paramItem.getMatchStrategy();
  97. if (!Arrays.asList(PARAM_MATCH_STRATEGY_EXACT, PARAM_MATCH_STRATEGY_CONTAINS, PARAM_MATCH_STRATEGY_REGEX).contains(matchStrategy)) {
  98. return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy);
  99. }
  100. itemEntity.setMatchStrategy(matchStrategy);
  101. }
  102. }
  103. }
  104. // 阈值类型 0-线程数 1-QPS
  105. Integer grade = reqVo.getGrade();
  106. if (grade == null) {
  107. return Result.ofFail(-1, "grade can't be null");
  108. }
  109. if (!Arrays.asList(FLOW_GRADE_THREAD, FLOW_GRADE_QPS).contains(grade)) {
  110. return Result.ofFail(-1, "invalid grade: " + grade);
  111. }
  112. entity.setGrade(grade);
  113. // QPS阈值
  114. Double count = reqVo.getCount();
  115. if (count == null) {
  116. return Result.ofFail(-1, "count can't be null");
  117. }
  118. if (count < 0) {
  119. return Result.ofFail(-1, "count should be at lease zero");
  120. }
  121. entity.setCount(count);
  122. // 间隔
  123. Long interval = reqVo.getInterval();
  124. if (interval == null) {
  125. return Result.ofFail(-1, "interval can't be null");
  126. }
  127. if (interval <= 0) {
  128. return Result.ofFail(-1, "interval should be greater than zero");
  129. }
  130. entity.setInterval(interval);
  131. // 间隔单位
  132. Integer intervalUnit = reqVo.getIntervalUnit();
  133. if (intervalUnit == null) {
  134. return Result.ofFail(-1, "intervalUnit can't be null");
  135. }
  136. if (!Arrays.asList(INTERVAL_UNIT_SECOND, INTERVAL_UNIT_MINUTE, INTERVAL_UNIT_HOUR, INTERVAL_UNIT_DAY).contains(intervalUnit)) {
  137. return Result.ofFail(-1, "Invalid intervalUnit: " + intervalUnit);
  138. }
  139. entity.setIntervalUnit(intervalUnit);
  140. // 流控方式 0-快速失败 2-匀速排队
  141. Integer controlBehavior = reqVo.getControlBehavior();
  142. if (controlBehavior == null) {
  143. return Result.ofFail(-1, "controlBehavior can't be null");
  144. }
  145. if (!Arrays.asList(CONTROL_BEHAVIOR_DEFAULT, CONTROL_BEHAVIOR_RATE_LIMITER).contains(controlBehavior)) {
  146. return Result.ofFail(-1, "invalid controlBehavior: " + controlBehavior);
  147. }
  148. entity.setControlBehavior(controlBehavior);
  149. if (CONTROL_BEHAVIOR_DEFAULT == controlBehavior) {
  150. // 0-快速失败, 则Burst size必填
  151. Integer burst = reqVo.getBurst();
  152. if (burst == null) {
  153. return Result.ofFail(-1, "burst can't be null");
  154. }
  155. if (burst < 0) {
  156. return Result.ofFail(-1, "invalid burst: " + burst);
  157. }
  158. entity.setBurst(burst);
  159. } else if (CONTROL_BEHAVIOR_RATE_LIMITER == controlBehavior) {
  160. // 1-匀速排队, 则超时时间必填
  161. Integer maxQueueingTimeoutMs = reqVo.getMaxQueueingTimeoutMs();
  162. if (maxQueueingTimeoutMs == null) {
  163. return Result.ofFail(-1, "maxQueueingTimeoutMs can't be null");
  164. }
  165. if (maxQueueingTimeoutMs < 0) {
  166. return Result.ofFail(-1, "invalid maxQueueingTimeoutMs: " + maxQueueingTimeoutMs);
  167. }
  168. entity.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs);
  169. }
  170. Date date = new Date();
  171. entity.setGmtCreate(date);
  172. entity.setGmtModified(date);
  173. try {
  174. entity = repository.save(entity);
  175. publishRules(entity.getApp(), entity.getIp(), entity.getPort());
  176. } catch (Throwable throwable) {
  177. logger.error("add gateway flow rule error:", throwable);
  178. return Result.ofThrowable(-1, throwable);
  179. }
  180. return Result.ofSuccess(entity);
  181. }
  182. @PostMapping("/save.json")
  183. public Result<GatewayFlowRuleEntity> updateFlowRule(HttpServletRequest request, @RequestBody UpdateFlowRuleReqVo reqVo) {
  184. AuthService.AuthUser authUser = authService.getAuthUser(request);
  185. String app = reqVo.getApp();
  186. if (StringUtil.isBlank(app)) {
  187. return Result.ofFail(-1, "app can't be null or empty");
  188. }
  189. authUser.authTarget(app, AuthService.PrivilegeType.WRITE_RULE);
  190. Long id = reqVo.getId();
  191. if (id == null) {
  192. return Result.ofFail(-1, "id can't be null");
  193. }
  194. GatewayFlowRuleEntity entity = repository.findById(id);
  195. if (entity == null) {
  196. return Result.ofFail(-1, "gateway flow rule does not exist, id=" + id);
  197. }
  198. // 针对请求属性
  199. GatewayParamFlowItemVo paramItem = reqVo.getParamItem();
  200. if (paramItem != null) {
  201. GatewayParamFlowItemEntity itemEntity = new GatewayParamFlowItemEntity();
  202. entity.setParamItem(itemEntity);
  203. // 参数属性 0-ClientIP 1-Remote Host 2-Header 3-URL参数 4-Cookie
  204. Integer parseStrategy = paramItem.getParseStrategy();
  205. if (!Arrays.asList(PARAM_PARSE_STRATEGY_CLIENT_IP, PARAM_PARSE_STRATEGY_HOST, PARAM_PARSE_STRATEGY_HEADER
  206. , PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
  207. return Result.ofFail(-1, "invalid parseStrategy: " + parseStrategy);
  208. }
  209. itemEntity.setParseStrategy(paramItem.getParseStrategy());
  210. // 当参数属性为2-Header 3-URL参数 4-Cookie时,参数名称必填
  211. if (Arrays.asList(PARAM_PARSE_STRATEGY_HEADER, PARAM_PARSE_STRATEGY_URL_PARAM, PARAM_PARSE_STRATEGY_COOKIE).contains(parseStrategy)) {
  212. // 参数名称
  213. String fieldName = paramItem.getFieldName();
  214. if (StringUtil.isBlank(fieldName)) {
  215. return Result.ofFail(-1, "fieldName can't be null or empty");
  216. }
  217. itemEntity.setFieldName(paramItem.getFieldName());
  218. String pattern = paramItem.getPattern();
  219. // 如果匹配串不为空,验证匹配模式
  220. if (StringUtil.isNotEmpty(pattern)) {
  221. itemEntity.setPattern(pattern);
  222. Integer matchStrategy = paramItem.getMatchStrategy();
  223. if (!Arrays.asList(PARAM_MATCH_STRATEGY_EXACT, PARAM_MATCH_STRATEGY_CONTAINS, PARAM_MATCH_STRATEGY_REGEX).contains(matchStrategy)) {
  224. return Result.ofFail(-1, "invalid matchStrategy: " + matchStrategy);
  225. }
  226. itemEntity.setMatchStrategy(matchStrategy);
  227. }
  228. }
  229. } else {
  230. entity.setParamItem(null);
  231. }
  232. // 阈值类型 0-线程数 1-QPS
  233. Integer grade = reqVo.getGrade();
  234. if (grade == null) {
  235. return Result.ofFail(-1, "grade can't be null");
  236. }
  237. if (!Arrays.asList(FLOW_GRADE_THREAD, FLOW_GRADE_QPS).contains(grade)) {
  238. return Result.ofFail(-1, "invalid grade: " + grade);
  239. }
  240. entity.setGrade(grade);
  241. // QPS阈值
  242. Double count = reqVo.getCount();
  243. if (count == null) {
  244. return Result.ofFail(-1, "count can't be null");
  245. }
  246. if (count < 0) {
  247. return Result.ofFail(-1, "count should be at lease zero");
  248. }
  249. entity.setCount(count);
  250. // 间隔
  251. Long interval = reqVo.getInterval();
  252. if (interval == null) {
  253. return Result.ofFail(-1, "interval can't be null");
  254. }
  255. if (interval <= 0) {
  256. return Result.ofFail(-1, "interval should be greater than zero");
  257. }
  258. entity.setInterval(interval);
  259. // 间隔单位
  260. Integer intervalUnit = reqVo.getIntervalUnit();
  261. if (intervalUnit == null) {
  262. return Result.ofFail(-1, "intervalUnit can't be null");
  263. }
  264. if (!Arrays.asList(INTERVAL_UNIT_SECOND, INTERVAL_UNIT_MINUTE, INTERVAL_UNIT_HOUR, INTERVAL_UNIT_DAY).contains(intervalUnit)) {
  265. return Result.ofFail(-1, "Invalid intervalUnit: " + intervalUnit);
  266. }
  267. entity.setIntervalUnit(intervalUnit);
  268. // 流控方式 0-快速失败 2-匀速排队
  269. Integer controlBehavior = reqVo.getControlBehavior();
  270. if (controlBehavior == null) {
  271. return Result.ofFail(-1, "controlBehavior can't be null");
  272. }
  273. if (!Arrays.asList(CONTROL_BEHAVIOR_DEFAULT, CONTROL_BEHAVIOR_RATE_LIMITER).contains(controlBehavior)) {
  274. return Result.ofFail(-1, "invalid controlBehavior: " + controlBehavior);
  275. }
  276. entity.setControlBehavior(controlBehavior);
  277. if (CONTROL_BEHAVIOR_DEFAULT == controlBehavior) {
  278. // 0-快速失败, 则Burst size必填
  279. Integer burst = reqVo.getBurst();
  280. if (burst == null) {
  281. return Result.ofFail(-1, "burst can't be null");
  282. }
  283. if (burst < 0) {
  284. return Result.ofFail(-1, "invalid burst: " + burst);
  285. }
  286. entity.setBurst(burst);
  287. } else if (CONTROL_BEHAVIOR_RATE_LIMITER == controlBehavior) {
  288. // 2-匀速排队, 则超时时间必填
  289. Integer maxQueueingTimeoutMs = reqVo.getMaxQueueingTimeoutMs();
  290. if (maxQueueingTimeoutMs == null) {
  291. return Result.ofFail(-1, "maxQueueingTimeoutMs can't be null");
  292. }
  293. if (maxQueueingTimeoutMs < 0) {
  294. return Result.ofFail(-1, "invalid maxQueueingTimeoutMs: " + maxQueueingTimeoutMs);
  295. }
  296. entity.setMaxQueueingTimeoutMs(maxQueueingTimeoutMs);
  297. }
  298. Date date = new Date();
  299. entity.setGmtModified(date);
  300. try {
  301. entity = repository.save(entity);
  302. publishRules(entity.getApp(), entity.getIp(), entity.getPort());
  303. } catch (Throwable throwable) {
  304. logger.error("update gateway flow rule error:", throwable);
  305. return Result.ofThrowable(-1, throwable);
  306. }
  307. return Result.ofSuccess(entity);
  308. }
  309. @PostMapping("/delete.json")
  310. public Result<Long> deleteFlowRule(HttpServletRequest request, Long id) {
  311. AuthService.AuthUser authUser = authService.getAuthUser(request);
  312. if (id == null) {
  313. return Result.ofFail(-1, "id can't be null");
  314. }
  315. GatewayFlowRuleEntity oldEntity = repository.findById(id);
  316. if (oldEntity == null) {
  317. return Result.ofSuccess(null);
  318. }
  319. authUser.authTarget(oldEntity.getApp(), AuthService.PrivilegeType.DELETE_RULE);
  320. try {
  321. repository.delete(id);
  322. publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort());
  323. } catch (Throwable throwable) {
  324. logger.error("delete gateway flow rule error:", throwable);
  325. return Result.ofThrowable(-1, throwable);
  326. }
  327. return Result.ofSuccess(id);
  328. }
  329. /**
  330. * <h3>发布规则统一逻辑</h3>
  331. *
  332. * <p>规则都是存在本地内存中的,先从内存中获取所有当前要发布规则应用的规则,是一个List</p>
  333. * <p>将全量的规则以一定的格式发布到数据源中,进行统一更新</p>
  334. *
  335. * @param app 应用名称
  336. * @param ip 应用IP
  337. * @param port 应用端口
  338. * @throws Exception 远程发布,会发生异常,要进行异常处理
  339. */
  340. private void publishRules(String app, String ip, Integer port) throws Exception {
  341. List<GatewayFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
  342. rulePublisher.publish(app, rules);
  343. }
  344. }

GatewayApiController 同理。

4) 修改前端代码

复制 resources.app.scripts.controllers.gateway.flow.js

-> resources.app.scripts.controllers.gateway.flow_v2.js

并修改 

GatewayFlowService -> GatewayFlowServiceV2

复制 resources.app.views.gateway.flow.html

-> resources.app.views.gateway.flow_v2.html

复制 resources/app/scripts/services/gateway/flow_service.js

-> resources/app/scripts/services/gateway/flow_service_v2.js

修改 GatewayFlowService -> GatewayFlowServiceV2 并 修改下面的url 加/v

修改 resources/app/scripts/app.js  为

//     .state("dashboard.gatewayFlow", {
//     templateUrl: "app/views/gateway/flow.html",
//     url: "/gateway/flow/:app",
//     controller: "GatewayFlowCtl",
//     resolve: {
//         loadMyFiles: ["$ocLazyLoad", function (e) {
//             return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/gateway/flow.js"]})
//         }]
//     }
// })
    .state('dashboard.gatewayFlowV2', {
        templateUrl: 'app/views/gateway/flow_v2.html',
        url: '/v2/gateway/flow/:app',
        controller: 'GatewayFlowCtlV2',
        resolve: {
            loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
                return $ocLazyLoad.load({
                    name: 'sentinelDashboardApp',
                    files: [
                        'app/scripts/controllers/gateway/flow_v2.js',
                    ]
                });
            }]
        }
    })

打包启动 发布规则后 在nacos 可查看到  发布的规则

注:

但我本地不适用这个 可以参考修改 resources/dist/js/app.js

resources/dist/js/app.js 修改后的代码为

  1. "use strict";
  2. var app;
  3. angular.module("sentinelDashboardApp", ["oc.lazyLoad", "ui.router", "ui.bootstrap", "angular-loading-bar", "ngDialog", "ui.bootstrap.datetimepicker", "ui-notification", "rzTable", "angular-clipboard", "selectize", "angularUtils.directives.dirPagination"]).factory("AuthInterceptor", ["$window", "$state", function (t, r) {
  4. return {
  5. responseError: function (e) {
  6. return 401 === e.status && (t.localStorage.removeItem("session_sentinel_admin"), r.go("login")), e
  7. }, response: function (e) {
  8. return e
  9. }, request: function (e) {
  10. return e
  11. }, requestError: function (e) {
  12. return e
  13. }
  14. }
  15. }]).config(["$stateProvider", "$urlRouterProvider", "$ocLazyLoadProvider", "$httpProvider", function (e, t, r, a) {
  16. a.interceptors.push("AuthInterceptor"), r.config({
  17. debug: !1,
  18. events: !0
  19. }), t.otherwise("/dashboard/home"), e.state("login", {
  20. url: "/login",
  21. templateUrl: "app/views/login.html",
  22. controller: "LoginCtl",
  23. resolve: {
  24. loadMyFiles: ["$ocLazyLoad", function (e) {
  25. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/login.js"]})
  26. }]
  27. }
  28. }).state("dashboard", {
  29. url: "/dashboard",
  30. templateUrl: "app/views/dashboard/main.html",
  31. resolve: {
  32. loadMyDirectives: ["$ocLazyLoad", function (e) {
  33. return e.load({
  34. name: "sentinelDashboardApp",
  35. files: ["app/scripts/directives/header/header.js", "app/scripts/directives/sidebar/sidebar.js", "app/scripts/directives/sidebar/sidebar-search/sidebar-search.js"]
  36. })
  37. }]
  38. }
  39. }).state("dashboard.home", {
  40. url: "/home",
  41. templateUrl: "app/views/dashboard/home.html",
  42. resolve: {
  43. loadMyFiles: ["$ocLazyLoad", function (e) {
  44. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/main.js"]})
  45. }]
  46. }
  47. }).state("dashboard.flowV1", {
  48. templateUrl: "app/views/flow_v1.html",
  49. url: "/flow/:app",
  50. controller: "FlowControllerV1",
  51. resolve: {
  52. loadMyFiles: ["$ocLazyLoad", function (e) {
  53. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/flow_v1.js"]})
  54. }]
  55. }
  56. }).state("dashboard.flow", {
  57. templateUrl: "app/views/flow_v2.html",
  58. url: "/v2/flow/:app",
  59. controller: "FlowControllerV2",
  60. resolve: {
  61. loadMyFiles: ["$ocLazyLoad", function (e) {
  62. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/flow_v2.js"]})
  63. }]
  64. }
  65. }).state("dashboard.paramFlow", {
  66. templateUrl: "app/views/param_flow.html",
  67. url: "/paramFlow/:app",
  68. controller: "ParamFlowController",
  69. resolve: {
  70. loadMyFiles: ["$ocLazyLoad", function (e) {
  71. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/param_flow.js"]})
  72. }]
  73. }
  74. }).state("dashboard.clusterAppAssignManage", {
  75. templateUrl: "app/views/cluster_app_assign_manage.html",
  76. url: "/cluster/assign_manage/:app",
  77. controller: "SentinelClusterAppAssignManageController",
  78. resolve: {
  79. loadMyFiles: ["$ocLazyLoad", function (e) {
  80. return e.load({
  81. name: "sentinelDashboardApp",
  82. files: ["app/scripts/controllers/cluster_app_assign_manage.js"]
  83. })
  84. }]
  85. }
  86. }).state("dashboard.clusterAppServerList", {
  87. templateUrl: "app/views/cluster_app_server_list.html",
  88. url: "/cluster/server/:app",
  89. controller: "SentinelClusterAppServerListController",
  90. resolve: {
  91. loadMyFiles: ["$ocLazyLoad", function (e) {
  92. return e.load({
  93. name: "sentinelDashboardApp",
  94. files: ["app/scripts/controllers/cluster_app_server_list.js"]
  95. })
  96. }]
  97. }
  98. }).state("dashboard.clusterAppClientList", {
  99. templateUrl: "app/views/cluster_app_client_list.html",
  100. url: "/cluster/client/:app",
  101. controller: "SentinelClusterAppTokenClientListController",
  102. resolve: {
  103. loadMyFiles: ["$ocLazyLoad", function (e) {
  104. return e.load({
  105. name: "sentinelDashboardApp",
  106. files: ["app/scripts/controllers/cluster_app_token_client_list.js"]
  107. })
  108. }]
  109. }
  110. }).state("dashboard.clusterSingle", {
  111. templateUrl: "app/views/cluster_single_config.html",
  112. url: "/cluster/single/:app",
  113. controller: "SentinelClusterSingleController",
  114. resolve: {
  115. loadMyFiles: ["$ocLazyLoad", function (e) {
  116. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/cluster_single.js"]})
  117. }]
  118. }
  119. }).state("dashboard.authority", {
  120. templateUrl: "app/views/authority.html",
  121. url: "/authority/:app",
  122. controller: "AuthorityRuleController",
  123. resolve: {
  124. loadMyFiles: ["$ocLazyLoad", function (e) {
  125. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/authority.js"]})
  126. }]
  127. }
  128. }).state("dashboard.degrade", {
  129. templateUrl: "app/views/degrade.html",
  130. url: "/degrade/:app",
  131. controller: "DegradeCtl",
  132. resolve: {
  133. loadMyFiles: ["$ocLazyLoad", function (e) {
  134. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/degrade.js"]})
  135. }]
  136. }
  137. }).state("dashboard.system", {
  138. templateUrl: "app/views/system.html",
  139. url: "/system/:app",
  140. controller: "SystemCtl",
  141. resolve: {
  142. loadMyFiles: ["$ocLazyLoad", function (e) {
  143. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/system.js"]})
  144. }]
  145. }
  146. }).state("dashboard.machine", {
  147. templateUrl: "app/views/machine.html",
  148. url: "/app/:app",
  149. controller: "MachineCtl",
  150. resolve: {
  151. loadMyFiles: ["$ocLazyLoad", function (e) {
  152. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/machine.js"]})
  153. }]
  154. }
  155. }).state("dashboard.identity", {
  156. templateUrl: "app/views/identity.html",
  157. url: "/identity/:app",
  158. controller: "IdentityCtl",
  159. resolve: {
  160. loadMyFiles: ["$ocLazyLoad", function (e) {
  161. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/identity.js"]})
  162. }]
  163. }
  164. }).state("dashboard.gatewayIdentity", {
  165. templateUrl: "app/views/gateway/identity.html",
  166. url: "/gateway/identity/:app",
  167. controller: "GatewayIdentityCtl",
  168. resolve: {
  169. loadMyFiles: ["$ocLazyLoad", function (e) {
  170. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/gateway/identity.js"]})
  171. }]
  172. }
  173. }).state("dashboard.metric", {
  174. templateUrl: "app/views/metric.html",
  175. url: "/metric/:app",
  176. controller: "MetricCtl",
  177. resolve: {
  178. loadMyFiles: ["$ocLazyLoad", function (e) {
  179. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/metric.js"]})
  180. }]
  181. }
  182. }).state("dashboard.gatewayApi", {
  183. templateUrl: "app/views/gateway/api.html",
  184. url: "/gateway/api/:app",
  185. controller: "GatewayApiCtl",
  186. resolve: {
  187. loadMyFiles: ["$ocLazyLoad", function (e) {
  188. return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/gateway/api.js"]})
  189. }]
  190. }
  191. })
  192. // .state("dashboard.gatewayFlow", {
  193. // templateUrl: "app/views/gateway/flow.html",
  194. // url: "/gateway/flow/:app",
  195. // controller: "GatewayFlowCtl",
  196. // resolve: {
  197. // loadMyFiles: ["$ocLazyLoad", function (e) {
  198. // return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/gateway/flow.js"]})
  199. // }]
  200. // }
  201. // })
  202. .state('dashboard.gatewayFlowV2', {
  203. templateUrl: 'app/views/gateway/flow_v2.html',
  204. url: '/v2/gateway/flow/:app',
  205. controller: 'GatewayFlowCtlV2',
  206. resolve: {
  207. loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
  208. return $ocLazyLoad.load({
  209. name: 'sentinelDashboardApp',
  210. files: [
  211. 'app/scripts/controllers/gateway/flow_v2.js',
  212. ]
  213. });
  214. }]
  215. }
  216. })
  217. }]), (app = angular.module("sentinelDashboardApp")).filter("range", [function () {
  218. return function (e, t) {
  219. if (isNaN(t) || t <= 0) return [];
  220. e = [];
  221. for (var r = 1; r <= t; r++) e.push(r);
  222. return e
  223. }
  224. }]), (app = angular.module("sentinelDashboardApp")).service("AuthService", ["$http", function (t) {
  225. this.login = function (e) {
  226. return t({url: "/auth/login", params: e, method: "POST"})
  227. }, this.logout = function () {
  228. return t({url: "/auth/logout", method: "POST"})
  229. }
  230. }]), (app = angular.module("sentinelDashboardApp")).service("AppService", ["$http", function (e) {
  231. this.getApps = function () {
  232. return e({url: "app/briefinfos.json", method: "GET"})
  233. }
  234. }]), (app = angular.module("sentinelDashboardApp")).service("FlowServiceV1", ["$http", function (a) {
  235. function t(e) {
  236. return void 0 === e || "" === e || isNaN(e) || e <= 0
  237. }
  238. this.queryMachineRules = function (e, t, r) {
  239. return a({url: "/v1/flow/rules", params: {app: e, ip: t, port: r}, method: "GET"})
  240. }, this.newRule = function (e) {
  241. e.resource, e.limitApp, e.grade, e.count, e.strategy, e.refResource, e.controlBehavior, e.warmUpPeriodSec, e.maxQueueingTimeMs, e.app, e.ip, e.port;
  242. return a({url: "/v1/flow/rule", data: e, method: "POST"})
  243. }, this.saveRule = function (e) {
  244. var t = {
  245. id: e.id,
  246. resource: e.resource,
  247. limitApp: e.limitApp,
  248. grade: e.grade,
  249. count: e.count,
  250. strategy: e.strategy,
  251. refResource: e.refResource,
  252. controlBehavior: e.controlBehavior,
  253. warmUpPeriodSec: e.warmUpPeriodSec,
  254. maxQueueingTimeMs: e.maxQueueingTimeMs
  255. };
  256. return a({url: "/v1/flow/save.json", params: t, method: "PUT"})
  257. }, this.deleteRule = function (e) {
  258. var t = {id: e.id, app: e.app};
  259. return a({url: "/v1/flow/delete.json", params: t, method: "DELETE"})
  260. }, this.checkRuleValid = function (e) {
  261. return void 0 === e.resource || "" === e.resource ? (alert("资源名称不能为空"), !1) : void 0 === e.count || e.count < 0 ? (alert("限流阈值必须大于等于 0"), !1) : void 0 === e.strategy || e.strategy < 0 ? (alert("无效的流控模式"), !1) : 1 != e.strategy && 2 != e.strategy || void 0 !== e.refResource && "" != e.refResource ? void 0 === e.controlBehavior || e.controlBehavior < 0 ? (alert("无效的流控整形方式"), !1) : 1 == e.controlBehavior && t(e.warmUpPeriodSec) ? (alert("预热时长必须大于 0"), !1) : 2 == e.controlBehavior && t(e.maxQueueingTimeMs) ? (alert("排队超时时间必须大于 0"), !1) : !e.clusterMode || void 0 !== e.clusterConfig && void 0 !== e.clusterConfig.thresholdType || (alert("集群限流配置不正确"), !1) : (alert("请填写关联资源或入口"), !1)
  262. }
  263. }]), (app = angular.module("sentinelDashboardApp")).service("FlowServiceV2", ["$http", function (a) {
  264. function t(e) {
  265. return void 0 === e || "" === e || isNaN(e) || e <= 0
  266. }
  267. this.queryMachineRules = function (e, t, r) {
  268. return a({url: "/v2/flow/rules", params: {app: e, ip: t, port: r}, method: "GET"})
  269. }, this.newRule = function (e) {
  270. return a({url: "/v2/flow/rule", data: e, method: "POST"})
  271. }, this.saveRule = function (e) {
  272. return a({url: "/v2/flow/rule/" + e.id, data: e, method: "PUT"})
  273. }, this.deleteRule = function (e) {
  274. return a({url: "/v2/flow/rule/" + e.id, method: "DELETE"})
  275. }, this.checkRuleValid = function (e) {
  276. return void 0 === e.resource || "" === e.resource ? (alert("资源名称不能为空"), !1) : void 0 === e.count || e.count < 0 ? (alert("限流阈值必须大于等于 0"), !1) : void 0 === e.strategy || e.strategy < 0 ? (alert("无效的流控模式"), !1) : 1 != e.strategy && 2 != e.strategy || void 0 !== e.refResource && "" != e.refResource ? void 0 === e.controlBehavior || e.controlBehavior < 0 ? (alert("无效的流控整形方式"), !1) : 1 == e.controlBehavior && t(e.warmUpPeriodSec) ? (alert("预热时长必须大于 0"), !1) : 2 == e.controlBehavior && t(e.maxQueueingTimeMs) ? (alert("排队超时时间必须大于 0"), !1) : !e.clusterMode || void 0 !== e.clusterConfig && void 0 !== e.clusterConfig.thresholdType || (alert("集群限流配置不正确"), !1) : (alert("请填写关联资源或入口"), !1)
  277. }
  278. }]), (app = angular.module("sentinelDashboardApp")).service("DegradeService", ["$http", function (a) {
  279. this.queryMachineRules = function (e, t, r) {
  280. return a({url: "degrade/rules.json", params: {app: e, ip: t, port: r}, method: "GET"})
  281. }, this.newRule = function (e) {
  282. var t = {
  283. id: e.id,
  284. resource: e.resource,
  285. limitApp: e.limitApp,
  286. count: e.count,
  287. timeWindow: e.timeWindow,
  288. grade: e.grade,
  289. app: e.app,
  290. ip: e.ip,
  291. port: e.port
  292. };
  293. return a({url: "/degrade/new.json", params: t, method: "GET"})
  294. }, this.saveRule = function (e) {
  295. var t = {
  296. id: e.id,
  297. resource: e.resource,
  298. limitApp: e.limitApp,
  299. grade: e.grade,
  300. count: e.count,
  301. timeWindow: e.timeWindow
  302. };
  303. return a({url: "/degrade/save.json", params: t, method: "GET"})
  304. }, this.deleteRule = function (e) {
  305. var t = {id: e.id, app: e.app};
  306. return a({url: "/degrade/delete.json", params: t, method: "GET"})
  307. }, this.checkRuleValid = function (e) {
  308. return void 0 === e.resource || "" === e.resource ? (alert("资源名称不能为空"), !1) : void 0 === e.grade || e.grade < 0 ? (alert("未知的降级策略"), !1) : void 0 === e.count || "" === e.count || e.count < 0 ? (alert("降级阈值不能为空或小于 0"), !1) : void 0 === e.timeWindow || "" === e.timeWindow || e.timeWindow <= 0 ? (alert("降级时间窗口必须大于 0"), !1) : !(1 == e.grade && 1 < e.count) || (alert("异常比率超出范围:[0.0 - 1.0]"), !1)
  309. }
  310. }]), (app = angular.module("sentinelDashboardApp")).service("SystemService", ["$http", function (a) {
  311. this.queryMachineRules = function (e, t, r) {
  312. return a({url: "system/rules.json", params: {app: e, ip: t, port: r}, method: "GET"})
  313. }, this.newRule = function (e) {
  314. var t = {app: e.app, ip: e.ip, port: e.port};
  315. return 0 == e.grade ? t.avgLoad = e.avgLoad : 1 == e.grade ? t.avgRt = e.avgRt : 2 == e.grade ? t.maxThread = e.maxThread : 3 == e.grade && (t.qps = e.qps), a({
  316. url: "/system/new.json",
  317. params: t,
  318. method: "GET"
  319. })
  320. }, this.saveRule = function (e) {
  321. var t = {id: e.id};
  322. return 0 == e.grade ? t.avgLoad = e.avgLoad : 1 == e.grade ? t.avgRt = e.avgRt : 2 == e.grade ? t.maxThread = e.maxThread : 3 == e.grade && (t.qps = e.qps), a({
  323. url: "/system/save.json",
  324. params: t,
  325. method: "GET"
  326. })
  327. }, this.deleteRule = function (e) {
  328. var t = {id: e.id, app: e.app};
  329. return a({url: "/system/delete.json", params: t, method: "GET"})
  330. }
  331. }]), (app = angular.module("sentinelDashboardApp")).service("MachineService", ["$http", "$httpParamSerializerJQLike", function (a, o) {
  332. this.getAppMachines = function (e) {
  333. return a({url: "app/" + e + "/machines.json", method: "GET"})
  334. }, this.removeAppMachine = function (e, t, r) {
  335. return a({
  336. url: "app/" + e + "/machine/remove.json",
  337. method: "POST",
  338. headers: {"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"},
  339. data: o({ip: t, port: r})
  340. })
  341. }
  342. }]), (app = angular.module("sentinelDashboardApp")).service("IdentityService", ["$http", function (a) {
  343. this.fetchIdentityOfMachine = function (e, t, r) {
  344. return a({url: "resource/machineResource.json", params: {ip: e, port: t, searchKey: r}, method: "GET"})
  345. }, this.fetchClusterNodeOfMachine = function (e, t, r) {
  346. return a({
  347. url: "resource/machineResource.json",
  348. params: {ip: e, port: t, type: "cluster", searchKey: r},
  349. method: "GET"
  350. })
  351. }
  352. }]), (app = angular.module("sentinelDashboardApp")).service("MetricService", ["$http", function (i) {
  353. this.queryAppSortedIdentities = function (e) {
  354. return i({url: "/metric/queryTopResourceMetric.json", params: e, method: "GET"})
  355. }, this.queryByAppAndIdentity = function (e) {
  356. return i({url: "/metric/queryByAppAndResource.json", params: e, method: "GET"})
  357. }, this.queryByMachineAndIdentity = function (e, t, r, a, o) {
  358. var l = {ip: e, port: t, identity: r, startTime: a.getTime(), endTime: o.getTime()};
  359. return i({url: "/metric/queryByAppAndResource.json", params: l, method: "GET"})
  360. }
  361. }]), angular.module("sentinelDashboardApp").service("ParamFlowService", ["$http", function (a) {
  362. function o(e) {
  363. return !("int" !== (r = e.classType) && "double" !== r && "float" !== r && "long" !== r && "short" !== r || void 0 !== (t = e.object) && "" !== t && !isNaN(t)) || (!!("byte" === e.classType && (a = e.object, o = -128, l = 127, void 0 === a || "" === a || isNaN(a) || a < o || l < a)) || (void 0 === e.object || void 0 === e.classType || (void 0 === (i = e.count) || "" === i || isNaN(i) || i < 0)));
  364. var t, r, a, o, l, i
  365. }
  366. this.queryMachineRules = function (e, t, r) {
  367. return a({url: "/paramFlow/rules", params: {app: e, ip: t, port: r}, method: "GET"})
  368. }, this.addNewRule = function (e) {
  369. return a({url: "/paramFlow/rule", data: e, method: "POST"})
  370. }, this.saveRule = function (e) {
  371. return a({url: "/paramFlow/rule/" + e.id, data: e, method: "PUT"})
  372. }, this.deleteRule = function (e) {
  373. return a({url: "/paramFlow/rule/" + e.id, method: "DELETE"})
  374. }, this.checkRuleValid = function (e) {
  375. if (!e.resource || "" === e.resource) return alert("资源名称不能为空"), !1;
  376. if (1 != e.grade) return alert("未知的限流模式"), !1;
  377. if (e.count < 0) return alert("限流阈值必须大于等于 0"), !1;
  378. if (void 0 === e.paramIdx || "" === e.paramIdx || isNaN(e.paramIdx) || e.paramIdx < 0) return alert("热点参数索引必须大于等于 0"), !1;
  379. if (void 0 !== e.paramFlowItemList) for (var t = 0; t < e.paramFlowItemList.length; t++) {
  380. var r = e.paramFlowItemList[t];
  381. if (o(r)) return alert("热点参数例外项不合法,请检查值和类型是否正确:参数为 " + r.object + ", 类型为 " + r.classType + ", 限流阈值为 " + r.count), !1
  382. }
  383. return !0
  384. }
  385. }]), angular.module("sentinelDashboardApp").service("AuthorityRuleService", ["$http", function (a) {
  386. this.queryMachineRules = function (e, t, r) {
  387. return a({url: "/authority/rules", params: {app: e, ip: t, port: r}, method: "GET"})
  388. }, this.addNewRule = function (e) {
  389. return a({url: "/authority/rule", data: e, method: "POST"})
  390. }, this.saveRule = function (e) {
  391. return a({url: "/authority/rule/" + e.id, data: e, method: "PUT"})
  392. }, this.deleteRule = function (e) {
  393. return a({url: "/authority/rule/" + e.id, method: "DELETE"})
  394. }, this.checkRuleValid = function (e) {
  395. return void 0 === e.resource || "" === e.resource ? (alert("资源名称不能为空"), !1) : void 0 === e.limitApp || "" === e.limitApp ? (alert("流控针对应用不能为空"), !1) : void 0 !== e.strategy || (alert("必须选择黑白名单模式"), !1)
  396. }
  397. }]), angular.module("sentinelDashboardApp").service("ClusterStateService", ["$http", function (a) {
  398. this.fetchClusterUniversalStateSingle = function (e, t, r) {
  399. return a({url: "/cluster/state_single", params: {app: e, ip: t, port: r}, method: "GET"})
  400. }, this.fetchClusterUniversalStateOfApp = function (e) {
  401. return a({url: "/cluster/state/" + e, method: "GET"})
  402. }, this.fetchClusterServerStateOfApp = function (e) {
  403. return a({url: "/cluster/server_state/" + e, method: "GET"})
  404. }, this.fetchClusterClientStateOfApp = function (e) {
  405. return a({url: "/cluster/client_state/" + e, method: "GET"})
  406. }, this.modifyClusterConfig = function (e) {
  407. return a({url: "/cluster/config/modify_single", data: e, method: "POST"})
  408. }, this.applyClusterFullAssignOfApp = function (e, t) {
  409. return a({url: "/cluster/assign/all_server/" + e, data: t, method: "POST"})
  410. }, this.applyClusterSingleServerAssignOfApp = function (e, t) {
  411. return a({url: "/cluster/assign/single_server/" + e, data: t, method: "POST"})
  412. }, this.applyClusterServerBatchUnbind = function (e, t) {
  413. return a({url: "/cluster/assign/unbind_server/" + e, data: t, method: "POST"})
  414. }
  415. }]), (app = angular.module("sentinelDashboardApp")).service("GatewayApiService", ["$http", function (a) {
  416. this.queryApis = function (e, t, r) {
  417. return a({url: "/gateway/api/list.json", params: {app: e, ip: t, port: r}, method: "GET"})
  418. }, this.newApi = function (e) {
  419. return a({url: "/gateway/api/new.json", data: e, method: "POST"})
  420. }, this.saveApi = function (e) {
  421. return a({url: "/gateway/api/save.json", data: e, method: "POST"})
  422. }, this.deleteApi = function (e) {
  423. var t = {id: e.id, app: e.app};
  424. return a({url: "/gateway/api/delete.json", params: t, method: "POST"})
  425. }, this.checkApiValid = function (e, t) {
  426. if (void 0 === e.apiName || "" === e.apiName) return alert("API名称不能为空"), !1;
  427. if (null == e.predicateItems || 0 === e.predicateItems.length) return alert("至少有一个匹配规则"), !1;
  428. for (var r = 0; r < e.predicateItems.length; r++) {
  429. var a = e.predicateItems[r].pattern;
  430. if (void 0 === a || "" === a) return alert("匹配串不能为空,请检查"), !1
  431. }
  432. return -1 === t.indexOf(e.apiName) || (alert("API名称(" + e.apiName + ")已存在"), !1)
  433. }
  434. }]), (app = angular.module("sentinelDashboardApp")).service("GatewayFlowService", ["$http", function (a) {
  435. this.queryRules = function (e, t, r) {
  436. return a({url: "/gateway/flow/list.json", params: {app: e, ip: t, port: r}, method: "GET"})
  437. }, this.newRule = function (e) {
  438. return a({url: "/gateway/flow/new.json", data: e, method: "POST"})
  439. }, this.saveRule = function (e) {
  440. return a({url: "/gateway/flow/save.json", data: e, method: "POST"})
  441. }, this.deleteRule = function (e) {
  442. var t = {id: e.id, app: e.app};
  443. return a({url: "/gateway/flow/delete.json", params: t, method: "POST"})
  444. }, this.checkRuleValid = function (e) {
  445. if (void 0 === e.resource || "" === e.resource) return alert("API名称不能为空"), !1;
  446. if (null != e.paramItem && (2 == e.paramItem.parseStrategy || 3 == e.paramItem.parseStrategy || 4 == e.paramItem.parseStrategy)) {
  447. if (void 0 === e.paramItem.fieldName || "" === e.paramItem.fieldName) return alert("当参数属性为Header、URL参数、Cookie时,参数名称不能为空"), !1;
  448. if ("" === e.paramItem.pattern) return alert("匹配串不能为空"), !1
  449. }
  450. return !(void 0 === e.count || e.count < 0) || (alert((1 === e.grade ? "QPS阈值" : "线程数") + "必须大于等于 0"), !1)
  451. }
  452. }]), (app = angular.module("sentinelDashboardApp")).service("GatewayFlowServiceV2", ["$http", function (a) {
  453. this.queryRules = function (e, t, r) {
  454. return a({url: "/v2/gateway/flow/list.json", params: {app: e, ip: t, port: r}, method: "GET"})
  455. }, this.newRule = function (e) {
  456. return a({url: "/v2/gateway/flow/new.json", data: e, method: "POST"})
  457. }, this.saveRule = function (e) {
  458. return a({url: "/v2/gateway/flow/save.json", data: e, method: "POST"})
  459. }, this.deleteRule = function (e) {
  460. var t = {id: e.id, app: e.app};
  461. return a({url: "/v2/gateway/flow/delete.json", params: t, method: "POST"})
  462. }, this.checkRuleValid = function (e) {
  463. if (void 0 === e.resource || "" === e.resource) return alert("API名称不能为空"), !1;
  464. if (null != e.paramItem && (2 == e.paramItem.parseStrategy || 3 == e.paramItem.parseStrategy || 4 == e.paramItem.parseStrategy)) {
  465. if (void 0 === e.paramItem.fieldName || "" === e.paramItem.fieldName) return alert("当参数属性为Header、URL参数、Cookie时,参数名称不能为空"), !1;
  466. if ("" === e.paramItem.pattern) return alert("匹配串不能为空"), !1
  467. }
  468. return !(void 0 === e.count || e.count < 0) || (alert((1 === e.grade ? "QPS阈值" : "线程数") + "必须大于等于 0"), !1)
  469. }
  470. }]);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/739417
推荐阅读
相关标签
  

闽ICP备14008679号