From 373c9af86739b16dee70ae65743b4678397fc714 Mon Sep 17 00:00:00 2001 From: 80003818 <80003818@sfmail.sf-express.com> Date: Mon, 18 Oct 2021 17:59:08 +0800 Subject: [PATCH] =?UTF-8?q?POST=E8=AF=B7=E6=B1=82=E4=B8=8D=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86=EF=BC=9A=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0contentType=20=E4=B8=8D=E5=AF=B9,=20body=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=20Header=20=E5=A4=B4=E9=83=A8AK=E7=A7=BB=E9=99=A4:=20?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E7=A7=BB=E9=99=A4=E5=BD=93=E5=89=8Drequest?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=B0=B1=E8=A1=8C=EF=BC=8C=E4=B8=8D=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-local.yml | 2 +- .../gateway/exception/AkRequireException.java | 14 + .../ContentTypeNotSupportedException.java | 14 + .../gateway/exception/GatewayException.java | 9 +- .../MethodNotSupportedException.java | 14 + .../gateway/exception/RateLimitException.java | 28 ++ .../exception/RuleExpiredException.java | 14 + .../exception/RuleNotExistException.java | 14 + .../gateway/filter/CustomerGlobalFilter.java | 278 +++++++++++------- .../com/ruoyi/gateway/utils/GatewayUtils.java | 64 ++-- .../src/main/resources/application-local.yml | 2 +- 11 files changed, 321 insertions(+), 132 deletions(-) create mode 100644 ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java create mode 100644 ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java create mode 100644 ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java create mode 100644 ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java create mode 100644 ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java create mode 100644 ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java diff --git a/ruoyi-admin/src/main/resources/application-local.yml b/ruoyi-admin/src/main/resources/application-local.yml index 3f94095ae..64181ee2d 100644 --- a/ruoyi-admin/src/main/resources/application-local.yml +++ b/ruoyi-admin/src/main/resources/application-local.yml @@ -78,7 +78,7 @@ spring: # 端口,默认为6379 port: 6379 # 数据库索引 - database: 0 + database: 11 # 密码 password: # 连接超时时间 diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java new file mode 100644 index 000000000..39747e4c4 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java @@ -0,0 +1,14 @@ +package com.ruoyi.gateway.exception; + +import lombok.NoArgsConstructor; + +/** + * 网关异常-AK必要 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +@NoArgsConstructor +public class AkRequireException extends GatewayException { + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java new file mode 100644 index 000000000..b5a5c9e2d --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java @@ -0,0 +1,14 @@ +package com.ruoyi.gateway.exception; + +import lombok.NoArgsConstructor; + +/** + * 网关异常-请求方法不支持 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +@NoArgsConstructor +public class ContentTypeNotSupportedException extends GatewayException { + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java index c4d4c969b..5b1311de5 100644 --- a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java @@ -1,11 +1,14 @@ package com.ruoyi.gateway.exception; +import lombok.NoArgsConstructor; + /** + * 网关异常 + * * @author Wenchao Gong * @date 2021-10-04 */ +@NoArgsConstructor public class GatewayException extends RuntimeException { - public GatewayException(String msg) { - super(msg); - } + } diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java new file mode 100644 index 000000000..42783bc10 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java @@ -0,0 +1,14 @@ +package com.ruoyi.gateway.exception; + +import lombok.NoArgsConstructor; + +/** + * 网关异常-请求方法不支持 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +@NoArgsConstructor +public class MethodNotSupportedException extends GatewayException { + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java new file mode 100644 index 000000000..cf3dbb349 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java @@ -0,0 +1,28 @@ +package com.ruoyi.gateway.exception; + +import cn.hutool.core.util.StrUtil; +import lombok.NoArgsConstructor; + +import java.util.concurrent.TimeUnit; + +/** + * 网关异常-限流异常 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +@NoArgsConstructor +public class RateLimitException extends GatewayException { + + private TimeUnit timeUnit; + private int replenishRate; + private int tokensLeft; + private String message; + public RateLimitException(int replenishRate, int tokensLeft, TimeUnit timeUnit) { + this.replenishRate = replenishRate; + this.tokensLeft = tokensLeft; + this.timeUnit = timeUnit; + String unit = StrUtil.upperFirst(timeUnit.name().toLowerCase()); + message = String.format("服务限流: 上限[%d/%s], 实际[%d/%s]", replenishRate, unit, tokensLeft, unit); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java new file mode 100644 index 000000000..e3d48deea --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java @@ -0,0 +1,14 @@ +package com.ruoyi.gateway.exception; + +import lombok.NoArgsConstructor; + +/** + * 网关异常-规则已过期 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +@NoArgsConstructor +public class RuleExpiredException extends GatewayException { + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java new file mode 100644 index 000000000..634d9d4e1 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java @@ -0,0 +1,14 @@ +package com.ruoyi.gateway.exception; + +import lombok.NoArgsConstructor; + +/** + * 网关异常-规则不存在 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +@NoArgsConstructor +public class RuleNotExistException extends GatewayException { + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java index 7287fee55..8e7bfbe61 100644 --- a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java @@ -1,9 +1,11 @@ package com.ruoyi.gateway.filter; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import com.ruoyi.gateway.exception.*; import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter; import com.ruoyi.gateway.utils.GatewayUtils; import com.ruoyi.gateway.utils.beans.IscRule; @@ -12,13 +14,13 @@ import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.springframework.util.StringUtils; import org.springframework.web.reactive.function.server.HandlerStrategies; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.server.ServerWebExchange; @@ -31,7 +33,6 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Supplier; import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setResponseStatus; import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; @@ -49,10 +50,12 @@ import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap */ public class CustomerGlobalFilter implements GlobalFilter, Ordered { private final CustomerRedisRateLimiter rateLimiter; + public CustomerGlobalFilter(CustomerRedisRateLimiter rateLimiter) { this.rateLimiter = rateLimiter; } - public static final TimeUnit[] TIME_UNITS = {TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS}; + + private static final TimeUnit[] TIME_UNITS = {TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS}; @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { @@ -64,75 +67,144 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered { final String accessKeyName = String.valueOf(metadata.get(GatewayUtils.CONFIG_ACCESS_KEY_NAME_KEY)); String headerAk = GatewayUtils.getValue(null, () -> request.getHeaders().get(accessKeyName)); if (HttpMethod.GET.equals(httpMethod)) { - final MultiValueMap queryParams = new LinkedMultiValueMap<>(request.getQueryParams()); - final IscRule rule = handleRule(headerAk, () -> queryParams.get(accessKeyName), route); - Supplier> rateLimiterAfterSupplier = () -> { - removeParam(headerAk, request, accessKeyName, () -> queryParams.remove(accessKeyName)); - handleHiddenParams(route, queryParams, (next, map) -> { - Object value; - if (Objects.isNull(value = next.getValue())) { - map.add(next.getKey(), StrUtil.EMPTY); - } else if (value instanceof JSONArray) { - map.put(next.getKey(), ((JSONArray) value).toList(String.class)); - } else { - map.add(next.getKey(), value.toString()); - } - }); - URI newUri = UriComponentsBuilder.fromUri(request.getURI()) - .replaceQueryParams(unmodifiableMultiValueMap(queryParams)).build().toUri(); - ServerHttpRequest updatedRequest = exchange.getRequest().mutate().uri(newUri).build(); - return chain.filter(exchange.mutate().request(updatedRequest).build()); - }; - - return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + return handleGetRequest(exchange, chain, route, request, accessKeyName, headerAk); } else if (HttpMethod.POST.equals(httpMethod)) { - final ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); - final Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> { + return handlePostRequest(exchange, chain, route, request, accessKeyName, headerAk); + } + throw new MethodNotSupportedException(); + } + + /** + * 处理POST 请求 + * + * @param exchange 当前服务交换器 + * @param chain 当前过滤链 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKeyName AK键名 + * @param headerAk 头部AK信息 + * @return 指示请求处理何时完成 + */ + private Mono handlePostRequest(ServerWebExchange exchange, GatewayFilterChain chain, Route route, + ServerHttpRequest request, String accessKeyName, String headerAk) { + final ServerRequest serverRequest = ServerRequest.create(exchange, + HandlerStrategies.withDefaults().messageReaders()); + final Mono modifiedBody = serverRequest.bodyToMono(String.class).defaultIfEmpty(StrUtil.EMPTY) + .flatMap(body -> { MediaType mediaType = request.getHeaders().getContentType(); if (MediaType.APPLICATION_JSON.equals(mediaType)) { - JSONObject jsonObj = JSONUtil.parseObj(body); - final IscRule rule = handleRule(headerAk, () -> - Arrays.asList(jsonObj.get(accessKeyName, String.class, true)), route); - Supplier> rateLimiterAfterSupplier = () -> { - removeParam(headerAk, request, accessKeyName, () -> jsonObj.remove(accessKeyName)); - handleHiddenParams(route, jsonObj, (next, map) -> { - map.set(next.getKey(), next.getValue()); - }); - return Mono.just(jsonObj.toString()); - }; - - return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + return handlePostRequestJson(exchange, route, request, accessKeyName, headerAk, body); } else if (MediaType.APPLICATION_FORM_URLENCODED.equals(mediaType)) { - if (StringUtils.hasText(body)) { - final Stream stream = Arrays.stream(body.split("&")).map(param -> param.split("=")); - final IscRule rule = handleRule(headerAk, () -> stream.filter(param -> param.length > 0 && - accessKeyName.equals(param[0])).map(param -> param[1]).collect(Collectors.toList()), route); - Supplier> rateLimiterAfterSupplier = () -> { - removeParam(headerAk, request, accessKeyName, null); - final List params = stream.filter(param -> !accessKeyName.equals(param[0])).collect(Collectors.toList()); - handleHiddenParams(route, params, (next, list) -> { - Object value; - if (Objects.isNull(value = next.getValue())) { - list.add(new String[]{next.getKey(), StrUtil.EMPTY}); - } else if (value instanceof JSONArray) { - ((JSONArray) value).stream().map(o -> String.valueOf(o)).forEach(v -> { - list.add(new String[]{next.getKey(), v}); - }); - } else { - list.add(new String[]{next.getKey(), next.getValue().toString()}); - } - }); - return Mono.just(params.stream().map(param -> param[0] + '=' + param[1]).collect(Collectors.joining("&"))); - }; - - return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); - } + return handlePostRequestFormUrlencoded(exchange, route, request, accessKeyName, headerAk, body); } - return Mono.empty(); + throw new ContentTypeNotSupportedException(); }); - return GatewayUtils.modifyBody(exchange, chain, modifiedBody); + return GatewayUtils.modifyBody(exchange, chain, modifiedBody); + } + + /** + * 处理POST APPLICATION_FORM_URLENCODED 请求 + * + * @param exchange 当前服务交换器 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKeyName AK键名 + * @param headerAk 头部AK信息 + * @param body 请求Body信息 + * @return 处理后的Body信息 + */ + private Mono handlePostRequestFormUrlencoded(ServerWebExchange exchange, Route route, + ServerHttpRequest request, String accessKeyName, + String headerAk, String body) { + + if (StrUtil.isBlank(body)) { + Assert.notBlank(headerAk, AkRequireException::new); } - return chain.filter(exchange); + final List srcParams = Arrays.stream(body.split("&")).map(param -> param.split("=")) + .collect(Collectors.toList()); + final IscRule rule = handleRule(headerAk, () -> srcParams.stream() + .filter(param -> param.length > 0 && accessKeyName.equals(param[0])) + .map(param -> param[1]).collect(Collectors.toList()), route); + Supplier> rateLimiterAfterSupplier = () -> { + removeParam(headerAk, request, accessKeyName, null); + final List params = srcParams.stream().filter(param -> !accessKeyName.equals(param[0])) + .collect(Collectors.toList()); + handleHiddenParams(route, params, (next, list) -> { + Object value; + if (Objects.isNull(value = next.getValue())) { + list.add(new String[]{next.getKey(), StrUtil.EMPTY}); + } else if (value instanceof JSONArray) { + ((JSONArray) value).stream().map(String::valueOf) + .forEach(v -> list.add(new String[]{next.getKey(), v})); + } else { + list.add(new String[]{next.getKey(), next.getValue().toString()}); + } + }); + return Mono.just(params.stream().map(param -> param[0] + '=' + param[1]).collect(Collectors.joining("&"))); + }; + + return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + } + + /** + * 处理POST APPLICATION_JSON 请求 + * + * @param exchange 当前服务交换器 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKeyName AK键名 + * @param headerAk 头部AK信息 + * @param body 请求Body信息 + * @return 处理后的Body信息 + */ + private Mono handlePostRequestJson(ServerWebExchange exchange, Route route, + ServerHttpRequest request, String accessKeyName, + String headerAk, String body) { + JSONObject jsonObj = StrUtil.isBlank(body) ? new JSONObject() : JSONUtil.parseObj(body); + final IscRule rule = handleRule(headerAk, () -> Collections.singletonList(jsonObj.get(accessKeyName, + String.class, true)), route); + Supplier> rateLimiterAfterSupplier = () -> { + removeParam(headerAk, request, accessKeyName, () -> jsonObj.remove(accessKeyName)); + handleHiddenParams(route, jsonObj, (next, map) -> map.set(next.getKey(), next.getValue())); + return Mono.just(jsonObj.toString()); + }; + + return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + } + + /** + * 处理GET 请求 + * + * @param exchange 当前服务交换器 + * @param chain 当前过滤链 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKeyName AK键名 + * @param headerAk 头部AK信息 + * @return 指示请求处理何时完成 + */ + private Mono handleGetRequest(ServerWebExchange exchange, GatewayFilterChain chain, Route route, + ServerHttpRequest request, String accessKeyName, String headerAk) { + final MultiValueMap queryParams = new LinkedMultiValueMap<>(request.getQueryParams()); + final IscRule rule = handleRule(headerAk, () -> queryParams.get(accessKeyName), route); + Supplier> rateLimiterAfterSupplier = () -> { + removeParam(headerAk, request, accessKeyName, () -> queryParams.remove(accessKeyName)); + handleHiddenParams(route, queryParams, (next, map) -> { + Object value; + if (Objects.isNull(value = next.getValue())) { + map.add(next.getKey(), StrUtil.EMPTY); + } else if (value instanceof JSONArray) { + map.put(next.getKey(), ((JSONArray) value).toList(String.class)); + } else { + map.add(next.getKey(), value.toString()); + } + }); + URI newUri = UriComponentsBuilder.fromUri(request.getURI()) + .replaceQueryParams(unmodifiableMultiValueMap(queryParams)).build().toUri(); + ServerHttpRequest updatedRequest = exchange.getRequest().mutate().uri(newUri).build(); + return chain.filter(exchange.mutate().request(updatedRequest).build()); + }; + return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); } @Override @@ -143,19 +215,19 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered { /** * 处理规则 * - * @param headerAk - * @param valueSupplier - * @param route - * @return + * @param headerAk 头部AK + * @param valueSupplier valueList 生产者 + * @param route 路由信息 + * @return AK对应服务规则信息 */ private IscRule handleRule(String headerAk, Supplier> valueSupplier, Route route) { //获取AK - final String ak = GatewayUtils.getValue(headerAk, valueSupplier, () -> new RuntimeException("AK 不存在")); + final String ak = GatewayUtils.getValue(headerAk, valueSupplier, AkRequireException::new); //获取规则 final IscRule rule = GatewayUtils.getRequiredValue(() -> GatewayUtils.getRule(ak, route.getId()), - () -> new RuntimeException("AK异常")); + RuleNotExistException::new); //是否到期 - GatewayUtils.isBefore(rule, () -> new RuntimeException("AK已过期")); + GatewayUtils.isBefore(rule, RuleExpiredException::new); //设置AK 到ID 为了传参方便 rule.setId(ak); return rule; @@ -163,18 +235,23 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered { /** * 删除参数 - * @param headerAk - * @param request - * @param accessKeyName - * @param removeSupplier - * @param + * + * @param headerAk 头部AK + * @param request 请求 + * @param accessKeyName AK名称 + * @param removeSupplier 删除参数提供者 + * @param 类型 */ - private void removeParam(String headerAk, ServerHttpRequest request, String accessKeyName, Supplier removeSupplier) { + private void removeParam(String headerAk, ServerHttpRequest request, String accessKeyName, + Supplier removeSupplier) { //如果header中有AK,则删除 if (Objects.nonNull(headerAk)) { - request.getHeaders().remove(accessKeyName); + final HttpHeaders headers = request.getHeaders(); + if(headers.containsKey(accessKeyName)) { + request.mutate().headers(headMap -> headMap.remove(accessKeyName)).build(); + } } - if(Objects.nonNull(removeSupplier)) { + if (Objects.nonNull(removeSupplier)) { removeSupplier.get(); } } @@ -182,10 +259,10 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered { /** * 处理隐藏参数 * - * @param route - * @param result - * @param mapper - * @param + * @param route 路由信息 + * @param result 参数 + * @param mapper 处理参数方法 + * @param 参数类型 */ private void handleHiddenParams(Route route, U result, BiConsumer, U> mapper) { final Object obj = route.getMetadata().get(GatewayUtils.CONFIG_ADD_PARAM_KEY); @@ -196,29 +273,29 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered { if (json.isEmpty()) { return; } - Iterator> iterator = json.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry next = iterator.next(); + for (Map.Entry next : json.entrySet()) { mapper.accept(next, result); } } /** * 限流 - * @param exchange - * @param rule - * @param route + * + * @param exchange 当前服务交换器 + * @param rule 限流规则 + * @param route 路由 * @param rateLimiterAfterSupplier 限流后操作(删除参数、添加隐藏参数,跳转) - * @param - * @return + * @param 最终返回类型 + * @return rateLimiterAfterSupplier 返回类型 */ - private Mono rateLimiter(ServerWebExchange exchange, IscRule rule, Route route, final int index, - Supplier> rateLimiterAfterSupplier) { + private Mono rateLimiter(ServerWebExchange exchange, IscRule rule, Route route, final int index, + Supplier> rateLimiterAfterSupplier) { final TimeUnit timeUnit = TIME_UNITS[index]; - final Long limit = TimeUnit.SECONDS.equals(timeUnit) ? rule.getSecondsLimit() : TimeUnit.MINUTES.equals(timeUnit) - ? rule.getMinutesLimit() : TimeUnit.HOURS.equals(timeUnit) ? rule.getHoursLimit() : rule.getDaysLimit(); - if(Objects.isNull(limit) || limit <= 0L) { - if(TimeUnit.DAYS.equals(timeUnit)) { + final Long limit = TimeUnit.SECONDS.equals(timeUnit) ? rule.getSecondsLimit() : + TimeUnit.MINUTES.equals(timeUnit) + ? rule.getMinutesLimit() : TimeUnit.HOURS.equals(timeUnit) ? rule.getHoursLimit() : rule.getDaysLimit(); + if (Objects.isNull(limit) || limit <= 0L) { + if (TimeUnit.DAYS.equals(timeUnit)) { return rateLimiterAfterSupplier.get(); } return rateLimiter(exchange, rule, route, index + 1, rateLimiterAfterSupplier); @@ -228,13 +305,14 @@ public class CustomerGlobalFilter implements GlobalFilter, Ordered { exchange.getResponse().getHeaders().add(header.getKey(), header.getValue()); } if (response.isAllowed()) { - if(TimeUnit.DAYS.equals(timeUnit)) { + if (TimeUnit.DAYS.equals(timeUnit)) { return rateLimiterAfterSupplier.get(); } return rateLimiter(exchange, rule, route, index + 1, rateLimiterAfterSupplier); } setResponseStatus(exchange, HttpStatus.TOO_MANY_REQUESTS); - return exchange.getResponse().setComplete(); + exchange.getResponse().setComplete(); + throw new RateLimitException(limit.intValue(), 1, timeUnit); }); } } diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java index 9cbfa0d20..107066969 100644 --- a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java @@ -44,41 +44,46 @@ public class GatewayUtils { public static final Codec RULE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRule.class); private static RedissonClient client = SpringUtil.getBean(RedissonClient.class); - public static Mono modifyBody(ServerWebExchange exchange, GatewayFilterChain chain, Mono publisher) - { + /** + * 修改请求Body + * + * @param exchange 当前服务交换器 + * @param chain 当前过滤链 + * @param publisher body体提供者 + * @return 指示请求处理何时完成 + */ + public static Mono modifyBody(ServerWebExchange exchange, GatewayFilterChain chain, Mono publisher) { BodyInserter bodyInserter = BodyInserters.fromPublisher(publisher, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); headers.remove(HttpHeaders.CONTENT_LENGTH); CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers); return bodyInserter.insert(outputMessage, new BodyInserterContext()) - .then(Mono.defer(() -> { - ServerHttpRequest decorator = decorate(exchange, headers, outputMessage); - return chain.filter(exchange.mutate().request(decorator).build()); - })); + .then(Mono.defer(() -> { + ServerHttpRequest request = decorate(exchange, headers, outputMessage); + return chain.filter(exchange.mutate().request(request).build()); + })); } - public static ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage) - { + public static ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, + CachedBodyOutputMessage outputMessage) { return new ServerHttpRequestDecorator(exchange.getRequest()) { - public HttpHeaders getHeaders() - { + @Override + public HttpHeaders getHeaders() { long contentLength = headers.getContentLength(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); - if (contentLength > 0L) - { + if (contentLength > 0L) { httpHeaders.setContentLength(contentLength); - } else - { + } else { httpHeaders.set("Transfer-Encoding", "chunked"); } return httpHeaders; } - public Flux getBody() - { + @Override + public Flux getBody() { return outputMessage.getBody(); } }; @@ -104,21 +109,21 @@ public class GatewayUtils { * @param * @return */ - public static String getValue(String before, Supplier> valueSupplier, Supplier errorMsgSupplier) - { - if(StringUtils.hasText(before)) { + public static String getValue(String before, Supplier> valueSupplier, + Supplier errorMsgSupplier) { + if (StringUtils.hasText(before)) { return before; } final List values = valueSupplier.get(); - if(CollectionUtil.isNotEmpty(values)) { + if (CollectionUtil.isNotEmpty(values)) { for (String value : values) { - if(StringUtils.hasText(value)) { + if (StringUtils.hasText(value)) { before = value; break; } } } - if(errorMsgSupplier != null) { + if (errorMsgSupplier != null) { Assert.notBlank(before, errorMsgSupplier); } return before; @@ -126,15 +131,17 @@ public class GatewayUtils { /** * 获取必要值,可抛出异常 + * * @param valueSupplier * @param errorMsgSupplier * @param * @param * @return */ - public static T getRequiredValue(Supplier valueSupplier, Supplier errorMsgSupplier) { + public static T getRequiredValue(Supplier valueSupplier, + Supplier errorMsgSupplier) { final T value = valueSupplier.get(); - if(Objects.nonNull(errorMsgSupplier)) { + if (Objects.nonNull(errorMsgSupplier)) { Assert.notNull(value, errorMsgSupplier); } return value; @@ -143,7 +150,8 @@ public class GatewayUtils { /** * 获取规则 - * @param ak AK + * + * @param ak AK * @param routeId 路由ID * @return */ @@ -154,11 +162,13 @@ public class GatewayUtils { /** * 断言是否超过结束时间 + * * @param rule * @param errorMsgSupplier * @param */ - public static void isBefore(IscRule rule, Supplier errorMsgSupplier) { - Assert.isTrue(Objects.nonNull(rule.getExpire()) && Date.from(Instant.now()).before(rule.getExpire()), errorMsgSupplier); + public static void isBefore(IscRule rule, Supplier errorMsgSupplier) { + Assert.isTrue(Objects.nonNull(rule.getExpire()) && Date.from(Instant.now()).before(rule.getExpire()), + errorMsgSupplier); } } diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml index 8edfcb289..4f07d97b8 100644 --- a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml @@ -21,7 +21,7 @@ spring: # 端口,默认为6379 port: 6379 # 数据库索引 - database: 0 + database: 11 # 密码 password: # 连接超时时间