From e80cd140646a8a8d72f66072a470a1e441d1507d Mon Sep 17 00:00:00 2001 From: akun <957746831@qq.com> Date: Fri, 24 May 2024 18:54:30 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BD=91=E5=85=B3=E9=80=BB=E8=BE=91=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf-admin/pom.xml | 1 + .../controller/GatewayServerController.java | 4 +- .../dto/InsertOrUpdateGatewayRouteDTO.java | 2 +- .../gateway/domain/vo/GatewayRouteListVO.java | 4 - .../domain/vo/GatewayServerDetailedVO.java | 2 +- .../domain/vo/GatewayServerListVO.java | 7 +- .../gateway/enums/GatewayRouteType.java | 45 - .../gateway/enums/GatewayServiceModel.java | 45 - .../gateway/enums/GatewayServiceType.java | 45 - .../impl/GatewayConfigServiceImpl.java | 2 +- .../service/impl/GatewayRouteServiceImpl.java | 2 + .../impl/GatewayServerServiceImpl.java | 4 +- .../java/com/sf/vertx/enums/GatewayError.java | 119 ++ .../com/sf/vertx/enums/GatewayRouteType.java | 38 + .../sf/vertx/enums/GatewayServiceModel.java | 38 + .../sf/vertx/enums/GatewayServiceType.java | 38 + sf-vertx/pom.xml | 5 + .../com/sf/vertx/constans/SACConstants.java | 21 + .../com/sf/vertx/constans/SacConstans.java | 7 - .../com/sf/vertx/constans/SacErrorCode.java | 55 - .../HttpMockException.java | 2 +- .../{handle => exception}/MockException.java | 2 +- .../sf/vertx/exception/ServiceException.java | 39 + .../sf/vertx/handle/ApiMockHandlerImpl.java | 13 +- .../vertx/handle/ApiRateLimitHandlerImpl.java | 19 +- .../com/sf/vertx/handle/AppConfigHandler.java | 1245 ++++++++--------- .../vertx/handle/AppRateLimitHandlerImpl.java | 12 +- .../com/sf/vertx/handle/BodyHandlerImpl.java | 161 +-- .../handle/OpenParameterCheckHandlerImpl.java | 50 + .../vertx/handle/ParameterCheckHandler.java | 18 +- .../handle/ParameterCheckHandlerImpl.java | 65 - .../handle/RestfulFailureHandlerImpl.java | 57 +- .../handle/SACParameterCheckHandlerImpl.java | 50 + .../com/sf/vertx/security/MainSecurity.java | 4 +- .../java/com/sf/vertx/security/RSAUtil.java | 237 ++-- .../java/com/sf/vertx/utils/AppUtils.java | 255 ++++ .../io/vertx/httpproxy/impl/ReverseProxy.java | 31 +- sf-vertx/src/main/resources/application.yml | 2 +- 38 files changed, 1483 insertions(+), 1263 deletions(-) delete mode 100644 sf-service/src/main/java/com/sf/service/gateway/enums/GatewayRouteType.java delete mode 100644 sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceModel.java delete mode 100644 sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceType.java create mode 100644 sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayError.java create mode 100644 sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayRouteType.java create mode 100644 sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceModel.java create mode 100644 sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceType.java create mode 100644 sf-vertx/src/main/java/com/sf/vertx/constans/SACConstants.java delete mode 100644 sf-vertx/src/main/java/com/sf/vertx/constans/SacConstans.java delete mode 100644 sf-vertx/src/main/java/com/sf/vertx/constans/SacErrorCode.java rename sf-vertx/src/main/java/com/sf/vertx/{handle => exception}/HttpMockException.java (96%) rename sf-vertx/src/main/java/com/sf/vertx/{handle => exception}/MockException.java (96%) create mode 100644 sf-vertx/src/main/java/com/sf/vertx/exception/ServiceException.java create mode 100644 sf-vertx/src/main/java/com/sf/vertx/handle/OpenParameterCheckHandlerImpl.java delete mode 100644 sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandlerImpl.java create mode 100644 sf-vertx/src/main/java/com/sf/vertx/handle/SACParameterCheckHandlerImpl.java create mode 100644 sf-vertx/src/main/java/com/sf/vertx/utils/AppUtils.java diff --git a/sf-admin/pom.xml b/sf-admin/pom.xml index 405cdd8..41ec012 100644 --- a/sf-admin/pom.xml +++ b/sf-admin/pom.xml @@ -76,6 +76,7 @@ com.smarterFramework sf-service + diff --git a/sf-service/src/main/java/com/sf/service/gateway/controller/GatewayServerController.java b/sf-service/src/main/java/com/sf/service/gateway/controller/GatewayServerController.java index 38f6b2b..918e4f7 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/controller/GatewayServerController.java +++ b/sf-service/src/main/java/com/sf/service/gateway/controller/GatewayServerController.java @@ -9,12 +9,10 @@ import com.sf.service.index.utils.AppUtils; import com.sf.service.gateway.domain.*; import com.sf.service.gateway.domain.dto.QueryGatewayServerDTO; import com.sf.service.gateway.domain.dto.UpdateDataStatusDTO; -import com.sf.service.gateway.domain.vo.GatewayInterfaceInfoListVO; import com.sf.service.gateway.domain.vo.GatewayServerDetailedVO; import com.sf.service.gateway.domain.vo.GatewayServerListVO; -import com.sf.service.gateway.domain.vo.GatewayStrategyListVO; import com.sf.service.gateway.enums.GatewayDataStatus; -import com.sf.service.gateway.enums.GatewayServiceModel; +import com.sf.vertx.enums.GatewayServiceModel; import com.sf.service.gateway.service.IGatewayInterfaceInfoService; import com.sf.service.gateway.service.IGatewayRouteService; import com.sf.service.gateway.service.IGatewayServerService; diff --git a/sf-service/src/main/java/com/sf/service/gateway/domain/dto/InsertOrUpdateGatewayRouteDTO.java b/sf-service/src/main/java/com/sf/service/gateway/domain/dto/InsertOrUpdateGatewayRouteDTO.java index 582ab28..e80b7f5 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/domain/dto/InsertOrUpdateGatewayRouteDTO.java +++ b/sf-service/src/main/java/com/sf/service/gateway/domain/dto/InsertOrUpdateGatewayRouteDTO.java @@ -2,7 +2,7 @@ package com.sf.service.gateway.domain.dto; import com.sf.common.annotation.Excel; import com.sf.service.gateway.domain.GatewayRoute; -import com.sf.service.gateway.enums.GatewayRouteType; +import com.sf.vertx.enums.GatewayRouteType; import com.sf.service.gateway.enums.RequestProtocol; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayRouteListVO.java b/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayRouteListVO.java index 8b4c76e..85a1938 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayRouteListVO.java +++ b/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayRouteListVO.java @@ -3,14 +3,10 @@ package com.sf.service.gateway.domain.vo; import com.alibaba.fastjson2.JSON; import com.sf.common.annotation.Excel; import com.sf.service.gateway.domain.GatewayRoute; -import com.sf.service.gateway.enums.GatewayRouteType; -import com.sf.service.gateway.enums.RequestProtocol; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import lombok.EqualsAndHashCode; import javax.validation.Valid; -import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.util.Date; diff --git a/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerDetailedVO.java b/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerDetailedVO.java index 75cc9e6..e609ae9 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerDetailedVO.java +++ b/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerDetailedVO.java @@ -2,7 +2,7 @@ package com.sf.service.gateway.domain.vo; import com.fasterxml.jackson.annotation.JsonFormat; import com.sf.service.gateway.domain.*; -import com.sf.service.gateway.enums.GatewayServiceModel; +import com.sf.vertx.enums.GatewayServiceModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; diff --git a/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerListVO.java b/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerListVO.java index 76b70f2..2cbc4f2 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerListVO.java +++ b/sf-service/src/main/java/com/sf/service/gateway/domain/vo/GatewayServerListVO.java @@ -1,17 +1,12 @@ package com.sf.service.gateway.domain.vo; import com.fasterxml.jackson.annotation.JsonFormat; -import com.sf.common.annotation.Excel; -import com.sf.common.core.domain.BaseEntity; import com.sf.service.gateway.domain.GatewayRoute; import com.sf.service.gateway.domain.GatewayServer; -import com.sf.service.gateway.enums.GatewayServiceModel; +import com.sf.vertx.enums.GatewayServiceModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import org.hibernate.validator.constraints.URL; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; import java.util.Date; /** diff --git a/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayRouteType.java b/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayRouteType.java deleted file mode 100644 index e8c9b59..0000000 --- a/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayRouteType.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.sf.service.gateway.enums; - -import org.springframework.util.StringUtils; - -/** - * 网关路由类型 - * - * @author zoukun - */ -public enum GatewayRouteType -{ - WEIGHT_ROUTE("WEIGHT_ROUTE", "权重路由策略"), - HEADER_ROUTE("HEADER_ROUTE", "请求头路由策略"), - ; - - private final String code; - private final String info; - - GatewayRouteType(String code, String info) - { - this.code = code; - this.info = info; - } - - public String getCode() - { - return code; - } - - public String getInfo() - { - return info; - } - - public static GatewayRouteType getByCode(String code){ - if (StringUtils.hasText(code)) { - for (GatewayRouteType value : GatewayRouteType.values()) { - if (value.code.equals(code)){ - return value; - } - } - } - return null; - } -} diff --git a/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceModel.java b/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceModel.java deleted file mode 100644 index 98a91f9..0000000 --- a/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceModel.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.sf.service.gateway.enums; - -import org.springframework.util.StringUtils; - -/** - * 网关服务模式 - * - * @author zoukun - */ -public enum GatewayServiceModel -{ - NORMAL("NORMAL", "普通模式"), - ROUTE("ROUTE", "路由模式"), - ; - - private final String code; - private final String info; - - GatewayServiceModel(String code, String info) - { - this.code = code; - this.info = info; - } - - public String getCode() - { - return code; - } - - public String getInfo() - { - return info; - } - - public static GatewayServiceModel getByCode(String code){ - if (StringUtils.hasText(code)) { - for (GatewayServiceModel value : GatewayServiceModel.values()) { - if (value.code.equals(code)){ - return value; - } - } - } - return null; - } -} diff --git a/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceType.java b/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceType.java deleted file mode 100644 index 0ec53a7..0000000 --- a/sf-service/src/main/java/com/sf/service/gateway/enums/GatewayServiceType.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.sf.service.gateway.enums; - -import org.springframework.util.StringUtils; - -/** - * 网关服务类型 - * - * @author zoukun - */ -public enum GatewayServiceType -{ - SAC("SAC", "SAC规范服务"), - OPEN("OPEN", "开放服务"), - ; - - private final String code; - private final String info; - - GatewayServiceType(String code, String info) - { - this.code = code; - this.info = info; - } - - public String getCode() - { - return code; - } - - public String getInfo() - { - return info; - } - - public static GatewayServiceType getByCode(String code){ - if (StringUtils.hasText(code)) { - for (GatewayServiceType value : GatewayServiceType.values()) { - if (value.code.equals(code)){ - return value; - } - } - } - return null; - } -} diff --git a/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayConfigServiceImpl.java b/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayConfigServiceImpl.java index 6aafb7c..fd64fcc 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayConfigServiceImpl.java +++ b/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayConfigServiceImpl.java @@ -13,7 +13,7 @@ import com.sf.common.utils.SecurityUtils; import com.sf.service.gateway.domain.*; import com.sf.service.gateway.enums.EncryptionAlgorithm; import com.sf.service.gateway.enums.GatewayDataStatus; -import com.sf.service.gateway.enums.GatewayServiceModel; +import com.sf.vertx.enums.GatewayServiceModel; import com.sf.service.gateway.enums.GatewayStrategyType; import com.sf.service.gateway.mapper.GatewayConfigMapper; import com.sf.service.gateway.service.*; diff --git a/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayRouteServiceImpl.java b/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayRouteServiceImpl.java index fc26adc..14e1c92 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayRouteServiceImpl.java +++ b/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayRouteServiceImpl.java @@ -17,6 +17,8 @@ import com.sf.service.gateway.enums.*; import com.sf.service.gateway.mapper.GatewayRouteMapper; import com.sf.service.gateway.service.IGatewayRouteService; import com.sf.service.gateway.service.IGatewayServerService; +import com.sf.vertx.enums.GatewayRouteType; +import com.sf.vertx.enums.GatewayServiceModel; import com.sf.vertx.enums.MatchType; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; diff --git a/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayServerServiceImpl.java b/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayServerServiceImpl.java index 79c0675..af5c768 100644 --- a/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayServerServiceImpl.java +++ b/sf-service/src/main/java/com/sf/service/gateway/service/impl/GatewayServerServiceImpl.java @@ -10,8 +10,8 @@ import com.sf.common.utils.URLUtils; import com.sf.service.gateway.domain.GatewayInterfaceInfo; import com.sf.service.gateway.domain.GatewayServer; import com.sf.service.gateway.enums.GatewayDataStatus; -import com.sf.service.gateway.enums.GatewayServiceModel; -import com.sf.service.gateway.enums.GatewayServiceType; +import com.sf.vertx.enums.GatewayServiceModel; +import com.sf.vertx.enums.GatewayServiceType; import com.sf.vertx.enums.RequestMethod; import com.sf.service.gateway.mapper.GatewayServerMapper; import com.sf.service.gateway.service.IGatewayInterfaceInfoService; diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayError.java b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayError.java new file mode 100644 index 0000000..5bc8914 --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayError.java @@ -0,0 +1,119 @@ +package com.sf.vertx.enums; + +/** + * VertX网关错误 + * + * @author zoukun + */ +public enum GatewayError { + // CLIENT ERROR + BAD_REQUEST(400, "Bad Request", ErrorType.CLIENT_ERROR), + UNAUTHORIZED(401, "Unauthorized", ErrorType.CLIENT_ERROR), + FORBIDDEN(403, "Forbidden", ErrorType.CLIENT_ERROR), + NOT_FOUND(404, "Not Found", ErrorType.CLIENT_ERROR), + METHOD_NOT_ALLOWED(405, "Method Not Allowed", ErrorType.CLIENT_ERROR), + NOT_ACCEPTABLE(406, "Not Acceptable", ErrorType.CLIENT_ERROR), + PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required", ErrorType.CLIENT_ERROR), + REQUEST_TIMEOUT(408, "Request Timeout", ErrorType.CLIENT_ERROR), + CONFLICT(409, "Conflict", ErrorType.CLIENT_ERROR), + GONE(410, "Gone", ErrorType.CLIENT_ERROR), + LENGTH_REQUIRED(411, "Length Required", ErrorType.CLIENT_ERROR), + PRECONDITION_FAILED(412, "Precondition Failed", ErrorType.CLIENT_ERROR), + PAYLOAD_TOO_LARGE(413, "Payload Too Large", ErrorType.CLIENT_ERROR), + URI_TOO_LONG(414, "URI Too Long", ErrorType.CLIENT_ERROR), + UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type", ErrorType.CLIENT_ERROR), + REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable", ErrorType.CLIENT_ERROR), + EXPECTATION_FAILED(417, "Expectation Failed", ErrorType.CLIENT_ERROR), + UNPROCESSABLE_ENTITY(422, "Unprocessable Entity", ErrorType.CLIENT_ERROR), + LOCKED(423, "Locked", ErrorType.CLIENT_ERROR), + FAILED_DEPENDENCY(424, "Failed Dependency", ErrorType.CLIENT_ERROR), + TOO_EARLY(425, "Too Early", ErrorType.CLIENT_ERROR), + UPGRADE_REQUIRED(426, "Upgrade Required", ErrorType.CLIENT_ERROR), + PRECONDITION_REQUIRED(428, "Precondition Required", ErrorType.CLIENT_ERROR), + TOO_MANY_REQUESTS(429, "Too Many Requests", ErrorType.CLIENT_ERROR), + REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large", ErrorType.CLIENT_ERROR), + UNAVAILABLE_FOR_LEGAL_REASONS(451, "Unavailable For Legal Reasons", ErrorType.CLIENT_ERROR), + + // SERVER_ERROR + INTERNAL_SERVER_ERROR(500, "Internal Server Error", ErrorType.SERVER_ERROR), + NOT_IMPLEMENTED(501, "Not Implemented", ErrorType.SERVER_ERROR), + BAD_GATEWAY(502, "Bad Gateway", ErrorType.SERVER_ERROR), + SERVICE_UNAVAILABLE(503, "Service Unavailable", ErrorType.SERVER_ERROR), + GATEWAY_TIMEOUT(504, "Gateway Timeout", ErrorType.SERVER_ERROR), + HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported", ErrorType.SERVER_ERROR), + INSUFFICIENT_STORAGE(507, "Insufficient Storage", ErrorType.SERVER_ERROR), + NOT_EXTENDED(510, "Not Extended", ErrorType.SERVER_ERROR), + NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required", ErrorType.SERVER_ERROR), + + // SERVICE_ERROR + DEFAULT_SERVICE_ERROR(10000, "Service request failed, please try again later", ErrorType.SERVICE_ERROR), // 默认业务错误提示 + APP_ACCESS_PROHIBITED(10001, "应用禁止访问,请联系管理员", ErrorType.SERVICE_ERROR), + APP_SERVICE_NOT_FOUND(10002, "APP service not found", ErrorType.SERVICE_ERROR), + API_SERVICE_NOT_FOUND(10003, "API service not found", ErrorType.SERVICE_ERROR), + PARAMETER_TRANSFER_ERROR(10010, "参数传递错误", ErrorType.SERVICE_ERROR), + UNABLE_TO_FIND_ROUTING_ADDRESS(10011, "无法找到路由地址", ErrorType.SERVICE_ERROR), + UNABLE_TO_FIND_MATCHING_ENCRYPTION_ALGORITHM(10012, "无法找到匹配的加解密算法", ErrorType.SERVICE_ERROR), + UNABLE_TO_FIND_MATCHING_CIRCUIT_BREAKER_STRATEGY(10013, "无法找到匹配的熔断策略", ErrorType.SERVICE_ERROR), + REVERSE_PROXY_EXECUTION_ERROR(10014, "反向代理执行错误", ErrorType.SERVICE_ERROR), + REQUEST_URL_RESTRICTED_BY_FLOW(10015, "请求url被限流", ErrorType.SERVICE_ERROR), + REQUEST_URL_IS_BROKEN(10016, "请求url被熔断", ErrorType.SERVICE_ERROR), + APP_REQUEST_URL_RESTRICTED_BY_FLOW(10017, "应用请求url被限流", ErrorType.SERVICE_ERROR), + ; + + private final int code; + private final String reasonPhrase; + + private final ErrorType errorType; + + GatewayError(int code, String reasonPhrase, ErrorType errorType) { + this.code = code; + this.reasonPhrase = reasonPhrase; + this.errorType = errorType; + } + + public int getCode() { + return code; + } + + public ErrorType getErrorType() { + return errorType; + } + + public String getReasonPhrase() { + return reasonPhrase; + } + + public static GatewayError getByCode(int code) { + for (GatewayError value : GatewayError.values()) { + if (value.code == code) { + return value; + } + } + return null; + } + + /** + * 网关错误类型 + */ + public enum ErrorType { + + CLIENT_ERROR(4), + SERVER_ERROR(5), + /** + * 业务错误,建议业务错误返回HTTP状态码为200,业务码放在返回信息当中。 + */ + SERVICE_ERROR(10), + ; + + private final int value; + + ErrorType(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + + } +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayRouteType.java b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayRouteType.java new file mode 100644 index 0000000..cf39442 --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayRouteType.java @@ -0,0 +1,38 @@ +package com.sf.vertx.enums; + + +/** + * 网关路由类型 + * + * @author zoukun + */ +public enum GatewayRouteType { + WEIGHT_ROUTE("WEIGHT_ROUTE", "权重路由策略"), + HEADER_ROUTE("HEADER_ROUTE", "请求头路由策略"), + ; + + private final String code; + private final String info; + + GatewayRouteType(String code, String info) { + this.code = code; + this.info = info; + } + + public String getCode() { + return code; + } + + public String getInfo() { + return info; + } + + public static GatewayRouteType getByCode(String code) { + for (GatewayRouteType value : GatewayRouteType.values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceModel.java b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceModel.java new file mode 100644 index 0000000..473bad6 --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceModel.java @@ -0,0 +1,38 @@ +package com.sf.vertx.enums; + + +/** + * 网关服务模式 + * + * @author zoukun + */ +public enum GatewayServiceModel { + NORMAL("NORMAL", "普通模式"), + ROUTE("ROUTE", "路由模式"), + ; + + private final String code; + private final String info; + + GatewayServiceModel(String code, String info) { + this.code = code; + this.info = info; + } + + public String getCode() { + return code; + } + + public String getInfo() { + return info; + } + + public static GatewayServiceModel getByCode(String code) { + for (GatewayServiceModel value : GatewayServiceModel.values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceType.java b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceType.java new file mode 100644 index 0000000..62dc635 --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayServiceType.java @@ -0,0 +1,38 @@ +package com.sf.vertx.enums; + + +/** + * 网关服务类型 + * + * @author zoukun + */ +public enum GatewayServiceType { + SAC("SAC", "SAC规范服务"), + OPEN("OPEN", "开放服务"), + ; + + private final String code; + private final String info; + + GatewayServiceType(String code, String info) { + this.code = code; + this.info = info; + } + + public String getCode() { + return code; + } + + public String getInfo() { + return info; + } + + public static GatewayServiceType getByCode(String code) { + for (GatewayServiceType value : GatewayServiceType.values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } +} diff --git a/sf-vertx/pom.xml b/sf-vertx/pom.xml index 75e6630..89b1e92 100644 --- a/sf-vertx/pom.xml +++ b/sf-vertx/pom.xml @@ -226,6 +226,11 @@ io.vertx vertx-consul-client + + org.apache.directory.studio + org.apache.commons.codec + 1.8 + diff --git a/sf-vertx/src/main/java/com/sf/vertx/constans/SACConstants.java b/sf-vertx/src/main/java/com/sf/vertx/constans/SACConstants.java new file mode 100644 index 0000000..4616207 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/constans/SACConstants.java @@ -0,0 +1,21 @@ +package com.sf.vertx.constans; + +public class SACConstants { + + public static final String CACHE_KEY_CONNECTOR = ":"; + + public static final String APP_CONFIG = "appConfig"; + + public static final String API_CONFIG = "apiConfig"; + + public static final String API_SERVICE_TYPE = "apiServiceType"; + + public static final String CIRCUIT_BREAKER = "CIRCUIT_BREAKER"; + + /** + * 业务码 key + */ + public static final String GATEWAY_SERVICE_CODE = "serviceCode"; + + +} diff --git a/sf-vertx/src/main/java/com/sf/vertx/constans/SacConstans.java b/sf-vertx/src/main/java/com/sf/vertx/constans/SacConstans.java deleted file mode 100644 index 8601a1e..0000000 --- a/sf-vertx/src/main/java/com/sf/vertx/constans/SacConstans.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sf.vertx.constans; - -public class SacConstans { - public static final String CACHE_KEY_CONNECTOR = ":"; - public static final String CIRCUIT_BREAKER = "CIRCUIT_BREAKER"; - -} diff --git a/sf-vertx/src/main/java/com/sf/vertx/constans/SacErrorCode.java b/sf-vertx/src/main/java/com/sf/vertx/constans/SacErrorCode.java deleted file mode 100644 index 13cee54..0000000 --- a/sf-vertx/src/main/java/com/sf/vertx/constans/SacErrorCode.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.sf.vertx.constans; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.lang3.StringUtils; - -import io.vertx.core.json.JsonObject; - -public class SacErrorCode { - public static final Integer DEFAULT_ERROR_CODE = 10000; - public final static Map _ERROR = new HashMap<>(); - static { - _ERROR.put(400, "Bad Request"); - _ERROR.put(401, "Unauthorized"); - _ERROR.put(403, "Forbidden"); - _ERROR.put(404, "Not Found"); - _ERROR.put(413, "Request Entity Too Large"); - _ERROR.put(415, "Unsupported Media Type"); - _ERROR.put(500, "Internal Server Error"); - _ERROR.put(502, "Bad Gateway"); - _ERROR.put(503, "Service Unavailable"); - _ERROR.put(504, "Gateway Timeout"); - _ERROR.put(504, "Gateway Timeout"); - _ERROR.put(10000, "服务请求失败,请稍后再试"); // 默认错误提示 - _ERROR.put(10001, "应用禁止访问,请联系管理员"); - _ERROR.put(10010, "无法找到路由地址"); - _ERROR.put(10011, "无法找到匹配的加解密算法"); - _ERROR.put(10012, "参数传递错误"); - _ERROR.put(10013, "无法匹配加解密、熔断代理模式"); - _ERROR.put(10014, "反向代理执行错误"); - _ERROR.put(10015, "请求url被限流"); - _ERROR.put(10016, "请求url被熔断"); - _ERROR.put(10017, "应用请求url被限流"); - _ERROR.put(10018, "apiCode与uri不匹配"); - _ERROR.put(10019, "请求不支持conetnt-type类型"); - _ERROR.put(10020, "uri返回mock数据"); - _ERROR.put(10021, "无法找到负载均衡路由节点"); - _ERROR.put(10022, "uri模糊匹配,不能使用加解密、熔断策略."); - }; - - public static JsonObject returnErrorMsg(Integer errorCode) { - JsonObject json = new JsonObject(); - String msg = _ERROR.get(errorCode); - if(StringUtils.isBlank(msg)) { - // default - json.put("code", DEFAULT_ERROR_CODE); - json.put("msg", _ERROR.get(DEFAULT_ERROR_CODE)); - } else { - json.put("code", errorCode); - json.put("msg", msg); - } - return json; - } -} diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/HttpMockException.java b/sf-vertx/src/main/java/com/sf/vertx/exception/HttpMockException.java similarity index 96% rename from sf-vertx/src/main/java/com/sf/vertx/handle/HttpMockException.java rename to sf-vertx/src/main/java/com/sf/vertx/exception/HttpMockException.java index 648a2f8..42d7af3 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/HttpMockException.java +++ b/sf-vertx/src/main/java/com/sf/vertx/exception/HttpMockException.java @@ -1,4 +1,4 @@ -package com.sf.vertx.handle; +package com.sf.vertx.exception; import io.netty.handler.codec.http.HttpResponseStatus; diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/MockException.java b/sf-vertx/src/main/java/com/sf/vertx/exception/MockException.java similarity index 96% rename from sf-vertx/src/main/java/com/sf/vertx/handle/MockException.java rename to sf-vertx/src/main/java/com/sf/vertx/exception/MockException.java index c2cfded..f41ee90 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/MockException.java +++ b/sf-vertx/src/main/java/com/sf/vertx/exception/MockException.java @@ -1,4 +1,4 @@ -package com.sf.vertx.handle; +package com.sf.vertx.exception; import io.netty.handler.codec.http.HttpResponseStatus; diff --git a/sf-vertx/src/main/java/com/sf/vertx/exception/ServiceException.java b/sf-vertx/src/main/java/com/sf/vertx/exception/ServiceException.java new file mode 100644 index 0000000..e3d4db6 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/exception/ServiceException.java @@ -0,0 +1,39 @@ +package com.sf.vertx.exception; + +import com.sf.vertx.enums.GatewayError; +import io.netty.handler.codec.http.HttpResponseStatus; + +/** + * 业务异常 + */ +public class ServiceException extends RuntimeException { + private static final long serialVersionUID = 7975954645547803572L; + private final int statusCode; + private final String payload; + + public ServiceException() { + this(GatewayError.DEFAULT_SERVICE_ERROR); + } + + public ServiceException(GatewayError gatewayError, String payload) { + this(gatewayError.getCode(), payload, null); + } + + public ServiceException(GatewayError gatewayError) { + this(gatewayError.getCode(), gatewayError.getReasonPhrase(), null); + } + + private ServiceException(int statusCode, String payload, Throwable cause) { + super("(" + statusCode + ")" + payload, cause, false, false); + this.statusCode = statusCode; + this.payload = payload; + } + + public int getStatusCode() { + return statusCode; + } + + public String getPayload() { + return payload; + } +} \ No newline at end of file diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/ApiMockHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/ApiMockHandlerImpl.java index 0cd50ca..6ea1057 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/ApiMockHandlerImpl.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/ApiMockHandlerImpl.java @@ -1,9 +1,11 @@ package com.sf.vertx.handle; import com.sf.vertx.api.pojo.MockResponse; -import com.sf.vertx.constans.SacErrorCode; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.MockException; +import com.sf.vertx.exception.ServiceException; +import com.sf.vertx.utils.AppUtils; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.HttpException; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -12,16 +14,15 @@ public class ApiMockHandlerImpl implements ApiMockHandler { @Override public void handle(RoutingContext rc) { try { - String cacheKey = AppConfigHandler.getApiCodeConfigCacheKey(rc); // mock - MockResponse mockResponse = AppConfigHandler.mock(cacheKey, rc); + MockResponse mockResponse = AppUtils.mock(rc); if (mockResponse != null) { rc.fail(new MockException(mockResponse.getHttpStatus(), mockResponse.getMockResponse())); return; } } catch (Exception e) { - e.printStackTrace(); - rc.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE)); + log.error("ApiMockHandlerImpl:",e); + rc.fail(new ServiceException(GatewayError.DEFAULT_SERVICE_ERROR)); return; } rc.next(); diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/ApiRateLimitHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/ApiRateLimitHandlerImpl.java index 8c59c00..6ce537a 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/ApiRateLimitHandlerImpl.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/ApiRateLimitHandlerImpl.java @@ -1,6 +1,8 @@ package com.sf.vertx.handle; import com.sf.vertx.constans.RedisKeyConfig; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.ServiceException; import com.sf.vertx.pojo.SacCurrentLimiting; import io.github.resilience4j.core.functions.CheckedRunnable; @@ -9,6 +11,8 @@ import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.HttpException; import lombok.extern.slf4j.Slf4j; +import static com.sf.vertx.constans.SACConstants.CACHE_KEY_CONNECTOR; + /*** * 内存存储 * @@ -20,31 +24,26 @@ public class ApiRateLimitHandlerImpl implements ApiRateLimitHandler { @Override public void handle(RoutingContext rc) { + log.info("Enter ApiRateLimitHandlerImpl.handle()"); String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey()); SacCurrentLimiting currentLimiting = AppConfigHandler.getApiCurrentLimiting(appCode, apiCode); if(currentLimiting != null) { - String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + ":" + appCode + ":" + apiCode + ":" + rc.request().uri() - + ":" + rc.request().method(); + String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + CACHE_KEY_CONNECTOR + appCode + CACHE_KEY_CONNECTOR + apiCode + CACHE_KEY_CONNECTOR + rc.request().uri() + + CACHE_KEY_CONNECTOR + rc.request().method(); RateLimiter rateLimiter = currentLimiting.getRegistry().rateLimiter(key); - CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, - () -> { - rc.next(); - return; - }); + CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, rc::next); try { restrictedCall.run(); } catch (Throwable t) { //t.printStackTrace(); log.info("api ratelimit:{}", key); - rc.fail(new HttpException(10015, currentLimiting.getStrategy().getDefaultResponse())); - return; + rc.fail(new ServiceException(GatewayError.REQUEST_URL_RESTRICTED_BY_FLOW, currentLimiting.getStrategy().getDefaultResponse())); } } else { rc.next(); - return; } } } diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/AppConfigHandler.java b/sf-vertx/src/main/java/com/sf/vertx/handle/AppConfigHandler.java index 15883d0..e6da943 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/AppConfigHandler.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/AppConfigHandler.java @@ -11,14 +11,15 @@ import java.util.concurrent.ConcurrentHashMap; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.NumberUtil; import com.sf.vertx.api.pojo.*; +import com.sf.vertx.enums.GatewayServiceType; import com.sf.vertx.enums.MatchType; import com.sf.vertx.enums.RequestMethod; import com.sf.vertx.security.MainSecurity; -import io.vertx.core.buffer.Buffer; +import com.sf.vertx.utils.AppUtils; import io.vertx.core.http.*; import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.RequestBody; import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.CorsHandler; import io.vertx.ext.web.handler.HttpException; import io.vertx.httpproxy.*; import org.apache.commons.lang3.StringUtils; @@ -54,6 +55,10 @@ import io.vertx.ext.web.client.WebClient; import io.vertx.spi.cluster.hazelcast.HazelcastClusterManager; import lombok.extern.slf4j.Slf4j; +import static com.sf.vertx.constans.SACConstants.API_CONFIG; +import static com.sf.vertx.constans.SACConstants.APP_CONFIG; + + /*** * vertx配置维护 * @@ -62,484 +67,355 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j public class AppConfigHandler { - private static VertxConfig VERTX_CONFIG = new VertxConfig(); - public static Vertx VERTX; - private static SacVertxConfig sacVertxConfig; - private static RedisTemplate redisTemplate; - public static CircuitBreaker CONNECTION_CIRCUIT_BREAKER; - // global cache app config - private static final ConcurrentHashMap CACHE_APP_CONFIG_MAP = new ConcurrentHashMap<>(); - // global api config appCode - RateLimiterRegistry - private static final ConcurrentHashMap GLOBAL_API_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>(); - // global app config appCode - Strategy - private static final ConcurrentHashMap GLOBAL_APP_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>(); - // appCode:apiCode:SacLoadBalancing - private static ConcurrentHashMap LOADBALANCING_MAP = new ConcurrentHashMap<>(); - // appCode:apiCode - ApiConfig - private static ConcurrentHashMap APICODE_CONFIG_MAP = new ConcurrentHashMap<>(); - // apiCode限流配置 appCode:apiCode - RateLimiterRegistry - private static ConcurrentHashMap APICODE_CONFIG_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>(); - // 服务类型, apiCode限流配置 appCode:apiCode - 服务类型,SAC=SAC规范服务,OPEN=开放服务 - private static ConcurrentHashMap APICODE_CONFIG_SERVICE_TYPE_MAP = new ConcurrentHashMap<>(); + private static VertxConfig VERTX_CONFIG = new VertxConfig(); + public static Vertx VERTX; + private static SacVertxConfig sacVertxConfig; + private static RedisTemplate redisTemplate; + public static CircuitBreaker CONNECTION_CIRCUIT_BREAKER; + // global cache app config + private static final ConcurrentHashMap CACHE_APP_CONFIG_MAP = new ConcurrentHashMap<>(); + // global api config appCode - RateLimiterRegistry + private static final ConcurrentHashMap GLOBAL_API_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>(); + // global app config appCode - Strategy + private static final ConcurrentHashMap GLOBAL_APP_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>(); + // appCode:apiCode:SacLoadBalancing + private static ConcurrentHashMap LOADBALANCING_MAP = new ConcurrentHashMap<>(); + // appCode:apiCode - ApiConfig + private static ConcurrentHashMap APICODE_CONFIG_MAP = new ConcurrentHashMap<>(); + // apiCode限流配置 appCode:apiCode - RateLimiterRegistry + private static ConcurrentHashMap APICODE_CONFIG_CURRENT_LIMITING_MAP = new ConcurrentHashMap<>(); + // 服务类型, apiCode限流配置 appCode:apiCode - 服务类型,SAC=SAC规范服务,OPEN=开放服务 + private static ConcurrentHashMap APICODE_CONFIG_SERVICE_TYPE_MAP = new ConcurrentHashMap<>(); - // 负载均衡路由类型 appCode:apiCode - routerType - // 执行流程 routerType=
- // 1、serviceNodel="NORMAL", serviceNodel="ROUTE" and RouteType = "WEIGHT_ROUTE" - //
- // return LOADBALANCING_MAP - // 2、serviceNodel="ROUTE", RouteType = "HEADER_ROUTE"
- // return APICODE_CONFIG_ROUTERCONENT_MAP - private static ConcurrentHashMap APICODE_CONFIG_ROUTERTYPE_MAP = new ConcurrentHashMap<>(); + // 负载均衡路由类型 appCode:apiCode - routerType + // 执行流程 routerType=
+ // 1、serviceNodel="NORMAL", serviceNodel="ROUTE" and RouteType = "WEIGHT_ROUTE" + //
+ // return LOADBALANCING_MAP + // 2、serviceNodel="ROUTE", RouteType = "HEADER_ROUTE"
+ // return APICODE_CONFIG_ROUTERCONENT_MAP + private static ConcurrentHashMap APICODE_CONFIG_ROUTERTYPE_MAP = new ConcurrentHashMap<>(); - private static ConcurrentHashMap> APICODE_CONFIG_HEADER_ROUTERCONENT_MAP = new ConcurrentHashMap<>(); - // apiCode熔断配置 appCode:apiCode - CircuitBreaker - private static ConcurrentHashMap APICODE_CONFIG_CIRCUIT_BREAKER_MAP = new ConcurrentHashMap<>(); + private static ConcurrentHashMap> APICODE_CONFIG_HEADER_ROUTERCONENT_MAP = new ConcurrentHashMap<>(); + // apiCode熔断配置 appCode:apiCode - CircuitBreaker + private static ConcurrentHashMap APICODE_CONFIG_CIRCUIT_BREAKER_MAP = new ConcurrentHashMap<>(); - // apicode uri = * - appConfig - private static ConcurrentHashMap APICODE_APPCONFIG_MAP = new ConcurrentHashMap<>(); + // apicode uri = * - appConfig + private static ConcurrentHashMap APICODE_APPCONFIG_MAP = new ConcurrentHashMap<>(); - // 禁用appCode - private static ConcurrentHashSet DISABLED_APPCODE = new ConcurrentHashSet(); + // 禁用appCode + private static ConcurrentHashSet DISABLED_APPCODE = new ConcurrentHashSet(); - public static AppConfig getAppConfigByDomain(String domain) { - return APICODE_APPCONFIG_MAP.get(domain); - } + public static AppConfig getAppConfigByDomain(String domain) { + return APICODE_APPCONFIG_MAP.get(domain); + } - public static Integer routerType(String key) { - return APICODE_CONFIG_ROUTERTYPE_MAP.get(key) != null ? APICODE_CONFIG_ROUTERTYPE_MAP.get(key) : 1; - } + public static Integer routerType(String key) { + return APICODE_CONFIG_ROUTERTYPE_MAP.get(key) != null ? APICODE_CONFIG_ROUTERTYPE_MAP.get(key) : 1; + } - public static List routerHeaderConentList(String key) { - return APICODE_CONFIG_HEADER_ROUTERCONENT_MAP.get(key); - } + public static List routerHeaderConentList(String key) { + return APICODE_CONFIG_HEADER_ROUTERCONENT_MAP.get(key); + } - public static Boolean isServiceTypeOpen(String key) { - return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null - && StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), "OPEN"); - } + public static Boolean isServiceTypeOpen(String key) { + return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null + && StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), "OPEN"); + } - public static Boolean isServiceTypeSac(String key) { - return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null - && StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), "SAC"); - } + public static Boolean isServiceTypeSac(String key) { + return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null + && StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), "SAC"); + } - public static String sacResponseHeaderKey() { - return sacVertxConfig.getSacResponseHeaderKey(); - } + public static String getServiceTypeOpen(String key) { + return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key); + } - public static String rpcUri() { - return sacVertxConfig.getRpcUri(); - } + public static String sacResponseHeaderKey() { + return sacVertxConfig.getSacResponseHeaderKey(); + } - public static void removeDisabledAppcode(String appCode) { - DISABLED_APPCODE.remove(appCode); - } + public static String rpcUri() { + return sacVertxConfig.getRpcUri(); + } - public static void addDisabledAppcode(String appCode) { - DISABLED_APPCODE.add(appCode); - } + public static void removeDisabledAppcode(String appCode) { + DISABLED_APPCODE.remove(appCode); + } - public static boolean isDisabledAppcode(String appCode) { - return DISABLED_APPCODE.contains(appCode); - } + public static void addDisabledAppcode(String appCode) { + DISABLED_APPCODE.add(appCode); + } - public static SacCurrentLimiting getGlobalAppCurrentLimitingConfig(String appCode) { - return GLOBAL_APP_CURRENT_LIMITING_MAP.get(appCode); - } + public static boolean isDisabledAppcode(String appCode) { + return DISABLED_APPCODE.contains(appCode); + } - public static AppConfig getAppConfig(String appCode) { - return CACHE_APP_CONFIG_MAP.get(appCode); - } + public static SacCurrentLimiting getGlobalAppCurrentLimitingConfig(String appCode) { + return GLOBAL_APP_CURRENT_LIMITING_MAP.get(appCode); + } - public static void init(RedisTemplate _redisTemplate, SacVertxConfig _sacVertxConfig) { - redisTemplate = _redisTemplate; - sacVertxConfig = _sacVertxConfig; - } + public static AppConfig getAppConfig(String appCode) { + return CACHE_APP_CONFIG_MAP.get(appCode); + } - public static boolean isDataSecurity(String appCode) { - return CACHE_APP_CONFIG_MAP.get(appCode) != null && CACHE_APP_CONFIG_MAP.get(appCode).getDataSecurity() != null - ? true - : false; - } + public static void init(RedisTemplate _redisTemplate, SacVertxConfig _sacVertxConfig) { + redisTemplate = _redisTemplate; + sacVertxConfig = _sacVertxConfig; + } - public static boolean isApiCodeCircuitBreaker(String key) { - return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key) != null ? true : false; - } + public static boolean isDataSecurity(String appCode) { + return CACHE_APP_CONFIG_MAP.get(appCode) != null && CACHE_APP_CONFIG_MAP.get(appCode).getDataSecurity() != null; + } - public static CircuitBreaker getApiCodeCircuitBreaker(String key) { - return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key); - } + public static boolean isApiCodeCircuitBreaker(String key) { + return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key) != null; + } - /*** - * 是否解析, 走独立请求 - * - * @return - */ - public static boolean isAnalysisBody(String appCode, String apiCode, String contentType) { - String apiCodeCacheKey = appCode + ":" + apiCode; - // Mock解析body - if (APICODE_CONFIG_MAP.get(apiCodeCacheKey) != null && APICODE_CONFIG_MAP.get(apiCodeCacheKey).getMockDefaultHttpStatus() != null){ - return true; - } - ApiConfig apicodeConfig = AppConfigHandler.getApicodeConfig(apiCodeCacheKey); - // 模糊匹配不解析body - String uri = apicodeConfig.getUri(); - if (StringUtils.equals(uri, "*")) { - return false; - } - // SAC请求方式GET,DELETE,HEAD请求需要解析body,SAC请求方式参数统一使用body传递,可能需要二次处理 - if (isServiceTypeSac(apiCodeCacheKey)){ - RequestMethod requestMethod = RequestMethod.getByCode(apicodeConfig.getMethod()); - if (RequestMethod.GET.equals(requestMethod) - || RequestMethod.DELETE.equals(requestMethod) - || RequestMethod.HEAD.equals(requestMethod)){ - return true; - } - } - if (StringUtils.startsWith(contentType, "multipart")){ - return false; - } - String keyCircuitBreaker = apiCodeCacheKey + ":" + "CIRCUIT_BREAKER"; - CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker); - boolean isDataSecurity = AppConfigHandler.isDataSecurity(appCode); - // 文件上传不走加解密 - return (isDataSecurity || circuitBreaker != null); - } + public static CircuitBreaker getApiCodeCircuitBreaker(String key) { + return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key); + } - /*** - * 优先apicode配置限流、无法找到匹配全局限流 - * - * @param appCode - * @param apiCode - * @return - */ - public static SacCurrentLimiting getApiCurrentLimiting(String appCode, String apiCode) { - String key = appCode + ":" + apiCode; - SacCurrentLimiting sacCurrentLimiting = APICODE_CONFIG_CURRENT_LIMITING_MAP.get(key) != null - ? APICODE_CONFIG_CURRENT_LIMITING_MAP.get(key) - : null; - sacCurrentLimiting = sacCurrentLimiting != null ? sacCurrentLimiting - : (GLOBAL_API_CURRENT_LIMITING_MAP.get(appCode) != null ? GLOBAL_API_CURRENT_LIMITING_MAP.get(appCode) - : null); - return sacCurrentLimiting; - } + /*** + * 是否解析, 走独立请求 + * + * @return + */ + public static boolean isAnalysisBody(String appCode, String apiCode, String contentType) { + String apiCodeCacheKey = appCode + ":" + apiCode; + // Mock解析body + if (APICODE_CONFIG_MAP.get(apiCodeCacheKey) != null && APICODE_CONFIG_MAP.get(apiCodeCacheKey).getMockDefaultHttpStatus() != null) { + return true; + } + ApiConfig apicodeConfig = AppConfigHandler.getApicodeConfig(apiCodeCacheKey); - public static VertxConfig getVertxConfig() { - return VERTX_CONFIG; - } + // SAC请求方式GET,DELETE,HEAD请求需要解析body,SAC请求方式参数统一使用body传递,可能需要二次处理 + if (isServiceTypeSac(apiCodeCacheKey)) { + RequestMethod requestMethod = RequestMethod.getByCode(apicodeConfig.getMethod()); + if (RequestMethod.GET.equals(requestMethod) + || RequestMethod.DELETE.equals(requestMethod) + || RequestMethod.HEAD.equals(requestMethod)) { + return true; + } + } + if (StringUtils.startsWith(contentType, "multipart")) { + return false; + } + String keyCircuitBreaker = apiCodeCacheKey + ":" + "CIRCUIT_BREAKER"; + CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker); + boolean isDataSecurity = AppConfigHandler.isDataSecurity(appCode); + // 文件上传不走加解密 + return (isDataSecurity || circuitBreaker != null); + } - public static String getAppCodeHeaderKey() { - return VERTX_CONFIG.getAppCodeHeaderKey(); - } + /*** + * 优先apicode配置限流、无法找到匹配全局限流 + * + * @param appCode + * @param apiCode + * @return + */ + public static SacCurrentLimiting getApiCurrentLimiting(String appCode, String apiCode) { + String key = appCode + ":" + apiCode; + SacCurrentLimiting sacCurrentLimiting = APICODE_CONFIG_CURRENT_LIMITING_MAP.get(key) != null + ? APICODE_CONFIG_CURRENT_LIMITING_MAP.get(key) + : null; + sacCurrentLimiting = sacCurrentLimiting != null ? sacCurrentLimiting + : (GLOBAL_API_CURRENT_LIMITING_MAP.get(appCode) != null ? GLOBAL_API_CURRENT_LIMITING_MAP.get(appCode) + : null); + return sacCurrentLimiting; + } - public static String getApiCodeHeaderKey() { - return VERTX_CONFIG.getApiCodeHeaderKey(); - } + public static VertxConfig getVertxConfig() { + return VERTX_CONFIG; + } - public static SacLoadBalancing getLoadBalancing(String key) { - return LOADBALANCING_MAP.get(key); - } + public static String getAppCodeHeaderKey() { + return VERTX_CONFIG.getAppCodeHeaderKey(); + } - public static ApiConfig getApicodeConfig(String key) { - return APICODE_CONFIG_MAP.get(key); - } + public static String getApiCodeHeaderKey() { + return VERTX_CONFIG.getApiCodeHeaderKey(); + } - public static Long getApicodeConfigTimeOut(String key) { - return APICODE_CONFIG_MAP.get(key) != null ? APICODE_CONFIG_MAP.get(key).getTimeout() : 3000L; - } + public static SacLoadBalancing getLoadBalancing(String key) { + return LOADBALANCING_MAP.get(key); + } - public static boolean isApicodeUri(String key, String uri, String httpMethod) { - String apiCodeUri = APICODE_CONFIG_MAP.get(key).getUri(); - if (StringUtils.equals(apiCodeUri, "*")) { - return true; - } - return StringUtils.equals(apiCodeUri, uri) - && StringUtils.equals(httpMethod, APICODE_CONFIG_MAP.get(key).getMethod()); - } + public static ApiConfig getApicodeConfig(String key) { + return APICODE_CONFIG_MAP.get(key); + } - public static MockResponse mock(String key, RoutingContext rc) { - if (APICODE_CONFIG_MAP.get(key) != null && APICODE_CONFIG_MAP.get(key).getMockDefaultHttpStatus() != null){ - String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); - // 如果是sac服务,query和body参数都从body中取 - Integer httpStatus = APICODE_CONFIG_MAP.get(key).getMockDefaultHttpStatus(); - String mockResponse = APICODE_CONFIG_MAP.get(key).getMockDefaultResponse(); - List mockExpectations = APICODE_CONFIG_MAP.get(key).getMockExpectations(); - if (mockExpectations != null && !mockExpectations.isEmpty()){ - String bodyStr = rc.body().asString(); - if (AppConfigHandler.isDataSecurity(appCode)) { - bodyStr = AppConfigHandler.bodyDecrypt(bodyStr, appCode); - } - JsonObject jsonBody = new JsonObject(bodyStr); - for (MockExpectation mockExpectation : mockExpectations) { - // 匹配条件需要全部匹配成功 - boolean matchSuccess = true; - for (MockMatchCondition matchCondition : mockExpectation.getMatchConditions()) { - if (!matchSuccess){ - break; - } - MatchType matchType = MatchType.getByCode(matchCondition.getMatchType()); - if (matchType == null) { - matchSuccess = false; - break; - } - String parameterPosition = matchCondition.getParameterPosition(); - String parameterKey = matchCondition.getParameterKey(); - List parameterValue = matchCondition.getParameterValue(); - String requestParameterValue = getRequestParameterValue(AppConfigHandler.isServiceTypeSac(key),parameterPosition,parameterKey,rc.request(),jsonBody); - if (!MatchType.IS_NULL.equals(matchType) && !MatchType.NOT_NULL.equals(matchType)){ - // 需要值而没有设置值,直接匹配失败 - if (CollectionUtil.isEmpty(parameterValue) || requestParameterValue == null) { - matchSuccess = false; - break; - } + public static Long getApicodeConfigTimeOut(String key) { + return APICODE_CONFIG_MAP.get(key) != null ? APICODE_CONFIG_MAP.get(key).getTimeout() : 3000L; + } + + + private static RateLimiterRegistry createRateLimiter(Strategy strategy) { + RateLimiterConfig config = RateLimiterConfig.custom() + .limitRefreshPeriod(Duration.ofSeconds(strategy.getTimeWindow())) + .limitForPeriod(strategy.getThreshold()).timeoutDuration(Duration.ofMillis(0)).build(); + RateLimiterRegistry registry = RateLimiterRegistry.of(config); + return registry; + } + + private static void initRateLimiter(String appCode, Strategy strategy, + ConcurrentHashMap map) { + RateLimiterRegistry registry = createRateLimiter(strategy); + SacCurrentLimiting sacCurrentLimiting = new SacCurrentLimiting(); + sacCurrentLimiting.setStrategy(strategy); + sacCurrentLimiting.setRegistry(registry); + map.put(appCode, sacCurrentLimiting); + } + + /*** + * 从redis加载数据 + * + * @throws Exception + */ + public static void initAllAppConfig() { + Set set = redisTemplate.opsForZSet().range(RedisKeyConfig.APP_CONFIG_SET_KEY, 0, -1); + for (String appCode : set) { + AppConfigHandler.initAppConfig(appCode, false); + } + } + + /*** + * 加载vertx配置 + */ + public static void initVertxConfig() { + String vertxConfigKey = RedisKeyConfig.VERTX_CONFIG_STRING_KEY; + String vertxConfigValue = redisTemplate.opsForValue().get(vertxConfigKey); + if (StringUtils.isNotBlank(vertxConfigValue)) { + VERTX_CONFIG = JSONObject.parseObject(vertxConfigValue, VertxConfig.class); + } + } + + private static void delAppConfigCache(String appCode) { + AppConfig appConfig = CACHE_APP_CONFIG_MAP.get(appCode); + if (appConfig != null) { + // app、api默认限流 + GLOBAL_API_CURRENT_LIMITING_MAP.remove(appCode); + GLOBAL_APP_CURRENT_LIMITING_MAP.remove(appCode); + for (SacService sacService : appConfig.getService()) { + if (sacService.getApiConfig() != null && sacService.getApiConfig().size() > 0) { + for (ApiConfig apiConfig : sacService.getApiConfig()) { + String key = appCode + ":" + apiConfig.getApiCode(); + APICODE_CONFIG_MAP.remove(key); + LOADBALANCING_MAP.remove(key); + APICODE_CONFIG_SERVICE_TYPE_MAP.remove(key); + APICODE_CONFIG_CURRENT_LIMITING_MAP.remove(key); + APICODE_APPCONFIG_MAP.remove(apiConfig.getApiCode()); + String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER"; + CircuitBreaker circuitBreaker = APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(keyCircuitBreaker); + if (circuitBreaker != null) { + circuitBreaker.close(); + APICODE_CONFIG_CIRCUIT_BREAKER_MAP.remove(keyCircuitBreaker); + } + } + } + } + // 应用配置 + CACHE_APP_CONFIG_MAP.remove(appCode); + } + } + + public static void initAppConfig(String appCode, boolean isDelLocalCache) { + // 是否需要先删除 + if (isDelLocalCache) { + delAppConfigCache(appCode); + } + + String appCodeKey = RedisKeyConfig.APP_CONFIG_PREFIX_KEY + ":" + appCode; + String appCodeValue = redisTemplate.opsForValue().get(appCodeKey); + if (StringUtils.isNotBlank(appCodeValue)) { + AppConfig appConfig = JSON.parseObject(appCodeValue, new TypeReference() { + }); + CACHE_APP_CONFIG_MAP.put(appCode, appConfig); + + // app、api默认限流 + if (appConfig.getApiCurrentLimitingConfig() != null) { + initRateLimiter(appCode, appConfig.getApiCurrentLimitingConfig(), GLOBAL_API_CURRENT_LIMITING_MAP); + } + + if (appConfig.getAppCurrentLimitingConfig() != null) { + initRateLimiter(appCode, appConfig.getAppCurrentLimitingConfig(), GLOBAL_APP_CURRENT_LIMITING_MAP); + } + + // app router负载均衡 + List routeContentList = null; + for (SacService sacService : appConfig.getService()) { + int routerType = 1; + List nodeList = new ArrayList<>(); + // 获取service模式 + if (StringUtils.equals(sacService.getServiceModel(), "NORMAL")) { + Node node = new Node(); + node.setIp(sacService.getServerAddress().getHost()); + node.setPort(sacService.getServerAddress().getPort()); + node.setWeight(0); + node.setProtocol(sacService.getServerAddress().getProtocol()); + nodeList.add(node); + } else if (StringUtils.equals(sacService.getServiceModel(), "ROUTE")) { + if (sacService.getRouteConfig() != null + && StringUtils.equals(sacService.getRouteConfig().getRouteType(), "WEIGHT_ROUTE")) { + for (RouteContent routeContent : sacService.getRouteConfig().getRouteContent()) { + Node node = new Node(); + node.setIp(routeContent.getServerAddress().getHost()); + node.setPort(routeContent.getServerAddress().getPort()); + node.setWeight(routeContent.getWeight() != null && routeContent.getWeight() > 0 + ? routeContent.getWeight() + : 1); + node.setProtocol(routeContent.getServerAddress().getProtocol()); + nodeList.add(node); + } + } else if (sacService.getRouteConfig() != null + && StringUtils.equals(sacService.getRouteConfig().getRouteType(), "HEADER_ROUTE")) { + routerType = 2; + routeContentList = sacService.getRouteConfig().getRouteContent(); + } + } + + // 初始化apiConfig + if (sacService.getApiConfig() != null && sacService.getApiConfig().size() > 0) { + for (ApiConfig apiConfig : sacService.getApiConfig()) { + String key = appCode + ":" + apiConfig.getApiCode(); + APICODE_CONFIG_MAP.put(key, apiConfig); + if (sacService.getServiceType() != null) { + APICODE_CONFIG_SERVICE_TYPE_MAP.put(key, sacService.getServiceType()); } - switch (matchType){ - case EQ: - matchSuccess = parameterValue.get(0).equals(requestParameterValue); - break; - case NOT_EQ: - matchSuccess = !parameterValue.get(0).equals(requestParameterValue); - break; - case GT: - if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { - matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) > 0; - }else { - matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) > 0; - } - break; - case GE: - if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { - matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) >= 0; - }else { - matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) >= 0; + // OPEN模式, 域名映射 + if (isServiceTypeOpen(key) && StringUtils.equals(apiConfig.getUri(), "*")) { + APICODE_APPCONFIG_MAP.put(apiConfig.getApiCode(), appConfig); + } + + // 负载均衡模式 + APICODE_CONFIG_ROUTERTYPE_MAP.put(key, routerType); + switch (routerType) { + case 1: + if (nodeList.size() > 0) { + // 初始化负载均衡算法 + SacLoadBalancing sacLoadBalancing = ProxyTool.roundRobin(nodeList); + LOADBALANCING_MAP.put(key, sacLoadBalancing); } break; - case LT: - if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { - matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) < 0; - }else { - matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) < 0; - } + case 2: + APICODE_CONFIG_HEADER_ROUTERCONENT_MAP.put(key, routeContentList); + default: break; - case LE: - if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { - matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) <= 0; - }else { - matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) <= 0; - } - break; - case IN: - matchSuccess = parameterValue.contains(requestParameterValue); - break; - case NOT_IN: - matchSuccess = !parameterValue.contains(requestParameterValue); - break; - case IS_NULL: - matchSuccess = requestParameterValue == null; - break; - case NOT_NULL: - matchSuccess = requestParameterValue != null; - break; - default: - break; - } + } - } - if (matchSuccess){ - httpStatus = mockExpectation.getHttpStatus(); - mockResponse = mockExpectation.getMockResponse(); - break; - } - } - } - - return new MockResponse(httpStatus,mockResponse); - } - return null; - } - - private static String getRequestParameterValue(Boolean isServiceTypeSac,String parameterPosition, String parameterKey, HttpServerRequest request,JsonObject jsonBody) { - switch (parameterPosition){ - case "query": - if (isServiceTypeSac){ - return jsonBody.getString(parameterKey); - } - return request.getParam(parameterKey); - case "header": - return request.getHeader(parameterKey); - case "body": - return jsonBody.getString(parameterKey); - default: - break; - } - return null; - } - - private static RateLimiterRegistry createRateLimiter(Strategy strategy) { - RateLimiterConfig config = RateLimiterConfig.custom() - .limitRefreshPeriod(Duration.ofSeconds(strategy.getTimeWindow())) - .limitForPeriod(strategy.getThreshold()).timeoutDuration(Duration.ofMillis(0)).build(); - RateLimiterRegistry registry = RateLimiterRegistry.of(config); - return registry; - } - - private static void initRateLimiter(String appCode, Strategy strategy, - ConcurrentHashMap map) { - RateLimiterRegistry registry = createRateLimiter(strategy); - SacCurrentLimiting sacCurrentLimiting = new SacCurrentLimiting(); - sacCurrentLimiting.setStrategy(strategy); - sacCurrentLimiting.setRegistry(registry); - map.put(appCode, sacCurrentLimiting); - } - - /*** - * 从redis加载数据 - * - * @throws Exception - */ - public static void initAllAppConfig() { - Set set = redisTemplate.opsForZSet().range(RedisKeyConfig.APP_CONFIG_SET_KEY, 0, -1); - for (String appCode : set) { - AppConfigHandler.initAppConfig(appCode, false); - } - } - - /*** - * 加载vertx配置 - */ - public static void initVertxConfig() { - String vertxConfigKey = RedisKeyConfig.VERTX_CONFIG_STRING_KEY; - String vertxConfigValue = redisTemplate.opsForValue().get(vertxConfigKey); - if (StringUtils.isNotBlank(vertxConfigValue)) { - VERTX_CONFIG = JSONObject.parseObject(vertxConfigValue, VertxConfig.class); - } - } - - private static void delAppConfigCache(String appCode) { - AppConfig appConfig = CACHE_APP_CONFIG_MAP.get(appCode); - if (appConfig != null) { - // app、api默认限流 - GLOBAL_API_CURRENT_LIMITING_MAP.remove(appCode); - GLOBAL_APP_CURRENT_LIMITING_MAP.remove(appCode); - for (SacService sacService : appConfig.getService()) { - if (sacService.getApiConfig() != null && sacService.getApiConfig().size() > 0) { - for (ApiConfig apiConfig : sacService.getApiConfig()) { - String key = appCode + ":" + apiConfig.getApiCode(); - APICODE_CONFIG_MAP.remove(key); - LOADBALANCING_MAP.remove(key); - APICODE_CONFIG_SERVICE_TYPE_MAP.remove(key); - APICODE_CONFIG_CURRENT_LIMITING_MAP.remove(key); - APICODE_APPCONFIG_MAP.remove(apiConfig.getApiCode()); - String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER"; - CircuitBreaker circuitBreaker = APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(keyCircuitBreaker); - if (circuitBreaker != null) { - circuitBreaker.close(); - APICODE_CONFIG_CIRCUIT_BREAKER_MAP.remove(keyCircuitBreaker); - } - } - } - } - // 应用配置 - CACHE_APP_CONFIG_MAP.remove(appCode); - } - } - - public static void initAppConfig(String appCode, boolean isDelLocalCache) { - // 是否需要先删除 - if (isDelLocalCache) { - delAppConfigCache(appCode); - } - - String appCodeKey = RedisKeyConfig.APP_CONFIG_PREFIX_KEY + ":" + appCode; - String appCodeValue = redisTemplate.opsForValue().get(appCodeKey); - if (StringUtils.isNotBlank(appCodeValue)) { - AppConfig appConfig = JSON.parseObject(appCodeValue, new TypeReference() { - }); - CACHE_APP_CONFIG_MAP.put(appCode, appConfig); - - // app、api默认限流 - if (appConfig.getApiCurrentLimitingConfig() != null) { - initRateLimiter(appCode, appConfig.getApiCurrentLimitingConfig(), GLOBAL_API_CURRENT_LIMITING_MAP); - } - - if (appConfig.getAppCurrentLimitingConfig() != null) { - initRateLimiter(appCode, appConfig.getAppCurrentLimitingConfig(), GLOBAL_APP_CURRENT_LIMITING_MAP); - } - - // app router负载均衡 - List routeContentList = null; - for (SacService sacService : appConfig.getService()) { - int routerType = 1; - List nodeList = new ArrayList<>(); - // 获取service模式 - if (StringUtils.equals(sacService.getServiceModel(), "NORMAL")) { - Node node = new Node(); - node.setIp(sacService.getServerAddress().getHost()); - node.setPort(sacService.getServerAddress().getPort()); - node.setWeight(0); - node.setProtocol(sacService.getServerAddress().getProtocol()); - nodeList.add(node); - } else if (StringUtils.equals(sacService.getServiceModel(), "ROUTE")) { - if (sacService.getRouteConfig() != null - && StringUtils.equals(sacService.getRouteConfig().getRouteType(), "WEIGHT_ROUTE")) { - for (RouteContent routeContent : sacService.getRouteConfig().getRouteContent()) { - Node node = new Node(); - node.setIp(routeContent.getServerAddress().getHost()); - node.setPort(routeContent.getServerAddress().getPort()); - node.setWeight(routeContent.getWeight() != null && routeContent.getWeight() > 0 - ? routeContent.getWeight() - : 1); - node.setProtocol(routeContent.getServerAddress().getProtocol()); - nodeList.add(node); - } - } else if (sacService.getRouteConfig() != null - && StringUtils.equals(sacService.getRouteConfig().getRouteType(), "HEADER_ROUTE")) { - routerType = 2; - routeContentList = sacService.getRouteConfig().getRouteContent(); - } - } - - // 初始化apiConfig - if (sacService.getApiConfig() != null && sacService.getApiConfig().size() > 0) { - for (ApiConfig apiConfig : sacService.getApiConfig()) { - String key = appCode + ":" + apiConfig.getApiCode(); - APICODE_CONFIG_MAP.put(key, apiConfig); - if(sacService.getServiceType() != null) { - APICODE_CONFIG_SERVICE_TYPE_MAP.put(key, sacService.getServiceType()); - } - - // OPEN模式, 域名映射 - if(isServiceTypeOpen(key) && StringUtils.equals(apiConfig.getUri(), "*")) { - APICODE_APPCONFIG_MAP.put(apiConfig.getApiCode(), appConfig); - } - - // 负载均衡模式 - APICODE_CONFIG_ROUTERTYPE_MAP.put(key, routerType); - switch (routerType) { - case 1: - if (nodeList.size() > 0) { - // 初始化负载均衡算法 - SacLoadBalancing sacLoadBalancing = ProxyTool.roundRobin(nodeList); - LOADBALANCING_MAP.put(key, sacLoadBalancing); - } - break; - case 2: - APICODE_CONFIG_HEADER_ROUTERCONENT_MAP.put(key, routeContentList); - default: - break; - } - - if (apiConfig.getStrategy() != null && apiConfig.getStrategy().size() > 0) { - for (Strategy strategy : apiConfig.getStrategy()) { - if (StringUtils.equals(strategy.getType(), "CURRENT_LIMITING")) { - RateLimiterRegistry registry = createRateLimiter(strategy); - SacCurrentLimiting sacCurrentLimiting = new SacCurrentLimiting(); - sacCurrentLimiting.setStrategy(strategy); - sacCurrentLimiting.setRegistry(registry); - APICODE_CONFIG_CURRENT_LIMITING_MAP.put(key, sacCurrentLimiting); - } else if (StringUtils.equals(strategy.getType(), "CIRCUIT_BREAKER")) { - String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER"; + if (apiConfig.getStrategy() != null && apiConfig.getStrategy().size() > 0) { + for (Strategy strategy : apiConfig.getStrategy()) { + if (StringUtils.equals(strategy.getType(), "CURRENT_LIMITING")) { + RateLimiterRegistry registry = createRateLimiter(strategy); + SacCurrentLimiting sacCurrentLimiting = new SacCurrentLimiting(); + sacCurrentLimiting.setStrategy(strategy); + sacCurrentLimiting.setRegistry(registry); + APICODE_CONFIG_CURRENT_LIMITING_MAP.put(key, sacCurrentLimiting); + } else if (StringUtils.equals(strategy.getType(), "CIRCUIT_BREAKER")) { + String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER"; // interfaceBreaker = CircuitBreaker.create("interfaceBreaker", VERTX, // new CircuitBreakerOptions().setMaxFailures(3).setMaxRetries(5).setTimeout(2000) // .setFallbackOnFailure(true) @@ -549,153 +425,153 @@ public class AppConfigHandler { // log.info("Circuit closed"); // });//.retryPolicy(retryCount -> retryCount * 100L); - // apiCode熔断 - CircuitBreaker circuitBreaker = CircuitBreaker - .create(keyCircuitBreaker + "-circuit-breaker", VERTX, - new CircuitBreakerOptions().setMaxFailures(strategy.getThreshold()) // 最大失败数 - .setFailuresRollingWindow(strategy.getTimeWindow() * 1000) // 毫秒 - //.setTimeout(apiConfig.getTimeout()) // 超时时间,不要开启, 配置会设置接口超时, 这个参数有bug,半开超时会卡死 - .setFallbackOnFailure(true) // 失败后是否调用回退函数(fallback) - .setResetTimeout(strategy.getRecovery_interval() * 1000) // 在开启状态下,尝试重试之前所需时间 - ).openHandler(v -> { - log.info(keyCircuitBreaker + " Circuit open"); - }).halfOpenHandler(v -> { - log.info(keyCircuitBreaker + "Circuit halfOpen"); - }).closeHandler(v -> { - log.info(keyCircuitBreaker + "Circuit close"); - }); - APICODE_CONFIG_CIRCUIT_BREAKER_MAP.put(keyCircuitBreaker, circuitBreaker); - } - } - } + // apiCode熔断 + CircuitBreaker circuitBreaker = CircuitBreaker + .create(keyCircuitBreaker + "-circuit-breaker", VERTX, + new CircuitBreakerOptions().setMaxFailures(strategy.getThreshold()) // 最大失败数 + .setFailuresRollingWindow(strategy.getTimeWindow() * 1000) // 毫秒 + //.setTimeout(apiConfig.getTimeout()) // 超时时间,不要开启, 配置会设置接口超时, 这个参数有bug,半开超时会卡死 + .setFallbackOnFailure(true) // 失败后是否调用回退函数(fallback) + .setResetTimeout(strategy.getRecovery_interval() * 1000) // 在开启状态下,尝试重试之前所需时间 + ).openHandler(v -> { + log.info(keyCircuitBreaker + " Circuit open"); + }).halfOpenHandler(v -> { + log.info(keyCircuitBreaker + "Circuit halfOpen"); + }).closeHandler(v -> { + log.info(keyCircuitBreaker + "Circuit close"); + }); + APICODE_CONFIG_CIRCUIT_BREAKER_MAP.put(keyCircuitBreaker, circuitBreaker); + } + } + } - } - } + } + } - } - } - } + } + } + } - public static void createVertx() { - // TODO 编解码线程池,后面优化协程等方式 - VertxOptions vertxOptions = new VertxOptions(); - loadVertxOptions(vertxOptions); - VERTX = Vertx.vertx(vertxOptions); + public static void createVertx() { + // TODO 编解码线程池,后面优化协程等方式 + VertxOptions vertxOptions = new VertxOptions(); + loadVertxOptions(vertxOptions); + VERTX = Vertx.vertx(vertxOptions); - initConnectionCircuitBreaker(); - createVertxRouter(); - consumerClusterEventMsg(); - } + initConnectionCircuitBreaker(); + createVertxRouter(); + consumerClusterEventMsg(); + } - private static Config hazelcastConfig(SacVertxConfig sacVertxConfig) { - // 集群 - Config hazelcastConfig = new Config(); - hazelcastConfig.setClusterName(sacVertxConfig.getClusterName()); // 集群名字 - NetworkConfig networkConfig = new NetworkConfig(); - networkConfig.setPort(sacVertxConfig.getNetworkPort()); - networkConfig.setPortAutoIncrement(sacVertxConfig.isPortAutoIncrement()); + private static Config hazelcastConfig(SacVertxConfig sacVertxConfig) { + // 集群 + Config hazelcastConfig = new Config(); + hazelcastConfig.setClusterName(sacVertxConfig.getClusterName()); // 集群名字 + NetworkConfig networkConfig = new NetworkConfig(); + networkConfig.setPort(sacVertxConfig.getNetworkPort()); + networkConfig.setPortAutoIncrement(sacVertxConfig.isPortAutoIncrement()); - JoinConfig join = new JoinConfig(); - TcpIpConfig tcpIpConfig = new TcpIpConfig(); - tcpIpConfig.setEnabled(true); - String[] clusterIps = sacVertxConfig.getClusterIp().split(","); - List members = Arrays.asList(clusterIps); - tcpIpConfig.setMembers(members); - join.setTcpIpConfig(tcpIpConfig); - networkConfig.setJoin(join); - hazelcastConfig.setNetworkConfig(networkConfig); + JoinConfig join = new JoinConfig(); + TcpIpConfig tcpIpConfig = new TcpIpConfig(); + tcpIpConfig.setEnabled(true); + String[] clusterIps = sacVertxConfig.getClusterIp().split(","); + List members = Arrays.asList(clusterIps); + tcpIpConfig.setMembers(members); + join.setTcpIpConfig(tcpIpConfig); + networkConfig.setJoin(join); + hazelcastConfig.setNetworkConfig(networkConfig); - // TODO 还有问题,不会使用 + // TODO 还有问题,不会使用 // ManagementCenterConfig managementCenterConfig = new ManagementCenterConfig(); // Set interfaces = new HashSet<>(); // interfaces.add("http://192.168.1.68:8080/mancenter"); // managementCenterConfig.setTrustedInterfaces(interfaces); // hazelcastConfig.setManagementCenterConfig(managementCenterConfig); - return hazelcastConfig; - } + return hazelcastConfig; + } - public static void createHazelcastClusterVertx() { - Config hazelcastConfig = hazelcastConfig(sacVertxConfig); - ClusterManager hazelcastClusterManager = new HazelcastClusterManager(hazelcastConfig); - // TODO 编解码线程池,后面优化协程等方式 - VertxOptions vertxOptions = new VertxOptions(); - loadVertxOptions(vertxOptions); - vertxOptions.setClusterManager(hazelcastClusterManager); - Vertx.clusteredVertx(vertxOptions, res -> { - if (res.succeeded()) { - VERTX = res.result(); - log.info("hazelcastClusterManager create success"); - initConnectionCircuitBreaker(); - createVertxRouter(); - consumerClusterEventMsg(); - } else { - res.cause().printStackTrace(); - log.info("hazelcastClusterManager create failure"); - } - }); - } + public static void createHazelcastClusterVertx() { + Config hazelcastConfig = hazelcastConfig(sacVertxConfig); + ClusterManager hazelcastClusterManager = new HazelcastClusterManager(hazelcastConfig); + // TODO 编解码线程池,后面优化协程等方式 + VertxOptions vertxOptions = new VertxOptions(); + loadVertxOptions(vertxOptions); + vertxOptions.setClusterManager(hazelcastClusterManager); + Vertx.clusteredVertx(vertxOptions, res -> { + if (res.succeeded()) { + VERTX = res.result(); + log.info("hazelcastClusterManager create success"); + initConnectionCircuitBreaker(); + createVertxRouter(); + consumerClusterEventMsg(); + } else { + res.cause().printStackTrace(); + log.info("hazelcastClusterManager create failure"); + } + }); + } - private static void consumerClusterEventMsg() { - // 订阅消息 - VERTX.eventBus().consumer("sac_cluster_event", message -> { - if (message.body() != null) { - ClusterEventMsg msg = JSONObject.parseObject(message.body().toString(), ClusterEventMsg.class); - log.info("Received message: {}", msg); - // message.reply("我是返回数据===" + message.body()); - if (msg.getType() == 1) { - if (msg.getOperation() == 1) { - // 初始化AppConfig本地缓存 - AppConfigHandler.initAppConfig(msg.getAppCode(), true); - } else if (msg.getOperation() == 3) { - // 删除本地缓存 - delAppConfigCache(msg.getAppCode()); - } else if (msg.getOperation() == 4) { - // 禁用app - addDisabledAppcode(msg.getAppCode()); - } else if (msg.getOperation() == 5) { - // 启用app - removeDisabledAppcode(msg.getAppCode()); - } - } - } - }); - } + private static void consumerClusterEventMsg() { + // 订阅消息 + VERTX.eventBus().consumer("sac_cluster_event", message -> { + if (message.body() != null) { + ClusterEventMsg msg = JSONObject.parseObject(message.body().toString(), ClusterEventMsg.class); + log.info("Received message: {}", msg); + // message.reply("我是返回数据===" + message.body()); + if (msg.getType() == 1) { + if (msg.getOperation() == 1) { + // 初始化AppConfig本地缓存 + AppConfigHandler.initAppConfig(msg.getAppCode(), true); + } else if (msg.getOperation() == 3) { + // 删除本地缓存 + delAppConfigCache(msg.getAppCode()); + } else if (msg.getOperation() == 4) { + // 禁用app + addDisabledAppcode(msg.getAppCode()); + } else if (msg.getOperation() == 5) { + // 启用app + removeDisabledAppcode(msg.getAppCode()); + } + } + } + }); + } - /*** - * 发布消息,订阅消息 - * - * @param msg - */ - public static void publishClusterEventMsg(ClusterEventMsg msg) { - VERTX.eventBus().publish("sac_cluster_event", JSONObject.toJSONString(msg)); - } + /*** + * 发布消息,订阅消息 + * + * @param msg + */ + public static void publishClusterEventMsg(ClusterEventMsg msg) { + VERTX.eventBus().publish("sac_cluster_event", JSONObject.toJSONString(msg)); + } - private static void createVertxRouter() { - // consul初始化 - // ConsulHandler.init(vertx); + private static void createVertxRouter() { + // consul初始化 + // ConsulHandler.init(vertx); - // 从redis同步app配置 - initAllAppConfig(); + // 从redis同步app配置 + initAllAppConfig(); - VertxConfig vertxConfig = AppConfigHandler.getVertxConfig(); - // 创建HTTP监听 - // 所有ip都能访问 - HttpServerOptions httpServerOptions = new HttpServerOptions().setHost("0.0.0.0"); - if (sacVertxConfig.isSSLs()) { - httpServerOptions.setSsl(true) - .setKeyStoreOptions(new JksOptions().setPassword("changeit").setPath("keystore.jks")); - } - HttpServer server = VERTX.createHttpServer(httpServerOptions); - Router mainHttpRouter = Router.router(VERTX); - Integer serverPort = vertxConfig.getPort() == null ? sacVertxConfig.getPort() : vertxConfig.getPort(); - log.info("serverPort:{}", serverPort); - server.requestHandler(mainHttpRouter).listen(serverPort, h -> { - if (h.succeeded()) { - log.info("HTTP端口监听成功:{}", serverPort); - } else { - log.error("HTTP端口监听失败:{}", serverPort); - } - }); + VertxConfig vertxConfig = AppConfigHandler.getVertxConfig(); + // 创建HTTP监听 + // 所有ip都能访问 + HttpServerOptions httpServerOptions = new HttpServerOptions().setHost("0.0.0.0"); + if (sacVertxConfig.isSSLs()) { + httpServerOptions.setSsl(true) + .setKeyStoreOptions(new JksOptions().setPassword("changeit").setPath("keystore.jks")); + } + HttpServer server = VERTX.createHttpServer(httpServerOptions); + Router mainHttpRouter = Router.router(VERTX); + Integer serverPort = vertxConfig.getPort() == null ? sacVertxConfig.getPort() : vertxConfig.getPort(); + log.info("serverPort:{}", serverPort); + server.requestHandler(mainHttpRouter).listen(serverPort, h -> { + if (h.succeeded()) { + log.info("HTTP端口监听成功:{}", serverPort); + } else { + log.error("HTTP端口监听失败:{}", serverPort); + } + }); // HttpClientOptions clientOptions = new HttpClientOptions(); // clientOptions.setMaxPoolSize(20); // 最大连接池大小 @@ -703,145 +579,124 @@ public class AppConfigHandler { // clientOptions.setHttp2KeepAliveTimeout(1); // clientOptions.setIdleTimeout(1000); // 连接空闲超时 毫秒 // HttpClient proxyClient = VERTX.createHttpClient(clientOptions); - HttpClient proxyClient = VERTX.createHttpClient(); - HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); - proxy.originSelector(request -> Future.succeededFuture(ProxyTool.resolveOriginAddress(request))); - proxy.addInterceptor(new ProxyInterceptor() { - @Override - public Future handleProxyRequest(ProxyContext context) { + HttpClient proxyClient = VERTX.createHttpClient(); + HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); + proxy.originSelector(request -> Future.succeededFuture(ProxyTool.resolveOriginAddress(request))); + proxy.addInterceptor(new ProxyInterceptor() { + @Override + public Future handleProxyRequest(ProxyContext context) { // if(StringUtils.equals(sacAppHeaderKey, "dsafdsfadafhappC")) { // // 会跳转到 RestfulFailureHandlerImpl // throw new HttpException(10003); // } - String appCode = context.request().headers().get(getAppCodeHeaderKey()); - String apiCode = context.request().headers().get(getApiCodeHeaderKey()); - String key = appCode + ":" + apiCode; - if (isServiceTypeSac(key)) { - String uri = APICODE_CONFIG_MAP.get(key).getUri(); - String method = APICODE_CONFIG_MAP.get(key).getMethod(); - context.request().setURI(uri).setMethod(HttpMethod.valueOf(method)); - } - return context.sendRequest(); - } + String appCode = context.request().headers().get(getAppCodeHeaderKey()); + String apiCode = context.request().headers().get(getApiCodeHeaderKey()); + String key = appCode + ":" + apiCode; + if (isServiceTypeSac(key)) { + String uri = APICODE_CONFIG_MAP.get(key).getUri(); + String method = APICODE_CONFIG_MAP.get(key).getMethod(); + context.request().setURI(uri).setMethod(HttpMethod.valueOf(method)); + } + return context.sendRequest(); + } - @Override - public Future handleProxyResponse(ProxyContext context) { - // 调试代码,获取reponse body + @Override + public Future handleProxyResponse(ProxyContext context) { + // 调试代码,获取reponse body // Filter filter = new Filter(); // ProxyResponse proxyResponse = context.response(); // Body body = proxyResponse.getBody(); // proxyResponse.setBody(Body.body(filter.init(context.request().getURI(), body.stream(), false))); - // 继续拦截链 - return context.sendResponse(); - } - }); - WebClient mainWebClient = WebClient.create(VERTX); - String rateLimitModel = vertxConfig.getRateLimitModel(); - Route routeSac = mainHttpRouter.route(rpcUri()); - Route routeOpen = mainHttpRouter.route(); - routeSac.handler(ParameterCheckHandler.create()) - .handler(AppRateLimitHandler.create(rateLimitModel)) - .handler(ApiRateLimitHandler.create(rateLimitModel)) - .handler(BodyHandler.create()) - .handler(ApiMockHandler.create()) - .handler(ProxyHandler.create(mainWebClient, proxy)) - .failureHandler(RestfulFailureHandler.create()); + // 继续拦截链 + return context.sendResponse(); + } + }); + WebClient mainWebClient = WebClient.create(VERTX); + String rateLimitModel = vertxConfig.getRateLimitModel(); + Route routeSac = mainHttpRouter.post(rpcUri()); + routeSac.handler(CorsHandler.create().addRelativeOrigin(".*")) + .handler(ParameterCheckHandler.create(GatewayServiceType.SAC)) + .handler(AppRateLimitHandler.create(rateLimitModel)) + .handler(ApiRateLimitHandler.create(rateLimitModel)) + .handler(BodyHandler.create().setHandleFileUploads(false)) + .handler(ApiMockHandler.create()) + .handler(ProxyHandler.create(mainWebClient, proxy)) + .failureHandler(RestfulFailureHandler.create()); // mainHttpRouter.route().handler(ProxyHandler.create(mainWebClient, proxy)); - routeOpen.handler(ParameterCheckHandler.create()) - .handler(AppRateLimitHandler.create(rateLimitModel)) - .handler(ApiRateLimitHandler.create(rateLimitModel)) - .handler(BodyHandler.create()) - .handler(ApiMockHandler.create()) - .handler(ProxyHandler.create(mainWebClient, proxy)) - .failureHandler(RestfulFailureHandler.create()); - } + Route routeOpen = mainHttpRouter.route(); + routeOpen.handler(CorsHandler.create().addRelativeOrigin(".*")) + .handler(ParameterCheckHandler.create(GatewayServiceType.OPEN)) + .handler(AppRateLimitHandler.create(rateLimitModel)) + .handler(ApiRateLimitHandler.create(rateLimitModel)) + .handler(BodyHandler.create().setHandleFileUploads(false)) + .handler(ApiMockHandler.create()) + .handler(ProxyHandler.create(mainWebClient, proxy)) + .failureHandler(RestfulFailureHandler.create()); + } - /*** - * 初始化connection Breaker - */ - private static void initConnectionCircuitBreaker() { - CONNECTION_CIRCUIT_BREAKER = CircuitBreaker.create("connectionCircuitBreaker-circuit-breaker", VERTX, - new CircuitBreakerOptions().setMaxFailures(3) // 最大失败数 - .setTimeout(2000) // 超时时间 - .setFallbackOnFailure(true) // 失败后是否调用回退函数(fallback) - .setResetTimeout(10000) // 在开启状态下,尝试重试之前所需时间 - ).openHandler(v -> { - log.info("connectionCircuitBreaker Circuit open"); - }).halfOpenHandler(v -> { - log.info("connectionCircuitBreaker Circuit halfOpen"); - }).closeHandler(v -> { - log.info("connectionCircuitBreaker Circuit close"); - }); - } + /*** + * 初始化connection Breaker + */ + private static void initConnectionCircuitBreaker() { + CONNECTION_CIRCUIT_BREAKER = CircuitBreaker.create("connectionCircuitBreaker-circuit-breaker", VERTX, + new CircuitBreakerOptions().setMaxFailures(3) // 最大失败数 + .setTimeout(2000) // 超时时间 + .setFallbackOnFailure(true) // 失败后是否调用回退函数(fallback) + .setResetTimeout(10000) // 在开启状态下,尝试重试之前所需时间 + ).openHandler(v -> { + log.info("connectionCircuitBreaker Circuit open"); + }).halfOpenHandler(v -> { + log.info("connectionCircuitBreaker Circuit halfOpen"); + }).closeHandler(v -> { + log.info("connectionCircuitBreaker Circuit close"); + }); + } - private static void loadVertxOptions(VertxOptions vertxOptions) { - long blockedThreadCheckInterval = VERTX_CONFIG.getVertxOptionsConfig() == null ? -1 - : VERTX_CONFIG.getVertxOptionsConfig().getBlockedThreadCheckInterval(); - int workerPoolSize = VERTX_CONFIG == null || VERTX_CONFIG.getVertxOptionsConfig() == null ? -1 - : VERTX_CONFIG.getVertxOptionsConfig().getWorkerPoolSize(); - if (workerPoolSize != -1) { - vertxOptions.setWorkerPoolSize(workerPoolSize); - } + private static void loadVertxOptions(VertxOptions vertxOptions) { + long blockedThreadCheckInterval = VERTX_CONFIG.getVertxOptionsConfig() == null ? -1 + : VERTX_CONFIG.getVertxOptionsConfig().getBlockedThreadCheckInterval(); + int workerPoolSize = VERTX_CONFIG == null || VERTX_CONFIG.getVertxOptionsConfig() == null ? -1 + : VERTX_CONFIG.getVertxOptionsConfig().getWorkerPoolSize(); + if (workerPoolSize != -1) { + vertxOptions.setWorkerPoolSize(workerPoolSize); + } - // TODO - blockedThreadCheckInterval = 1000000L; - if (blockedThreadCheckInterval != -1) { - vertxOptions.setBlockedThreadCheckInterval(blockedThreadCheckInterval); // 不打印Thread blocked 阻塞日志 - } - } + // TODO + blockedThreadCheckInterval = 1000000L; + if (blockedThreadCheckInterval != -1) { + vertxOptions.setBlockedThreadCheckInterval(blockedThreadCheckInterval); // 不打印Thread blocked 阻塞日志 + } + } - public static String bodyEncrypt(String body, String appCode) { - DataSecurity dataSecurity = getAppConfig(appCode).getDataSecurity(); - switch (dataSecurity.getAlgorithm()) { - case "AES": - return MainSecurity.aesEncrypt(body, dataSecurity.getPrivateKey()); - case "RSA": - return MainSecurity.rsaEncrypt(body, dataSecurity.getPublicKey()); - default: - break; - } - log.info(" appCode:{}, encrypt key config is error.", appCode); - throw new HttpException(10011); - } + public static String bodyEncrypt(String body, String appCode) { + DataSecurity dataSecurity = getAppConfig(appCode).getDataSecurity(); + switch (dataSecurity.getAlgorithm()) { + case "AES": + return MainSecurity.aesEncrypt(body, dataSecurity.getPrivateKey()); + case "RSA": + return MainSecurity.rsaEncrypt(body, dataSecurity.getPublicKey()); + default: + break; + } + log.info(" appCode:{}, encrypt key config is error.", appCode); + throw new HttpException(10011); + } - public static String bodyDecrypt(String body, String appCode) { - DataSecurity dataSecurity = getAppConfig(appCode).getDataSecurity(); - switch (dataSecurity.getAlgorithm()) { - case "AES": - return MainSecurity.aesDecrypt(body, dataSecurity.getPrivateKey()); - case "RSA": - return MainSecurity.rsaDecrypt(body, dataSecurity.getPrivateKey()); - default: - break; - } - log.info(" appCode:{}, decrypt key config is error.", appCode); - throw new HttpException(10011); - } + public static String bodyDecrypt(String body, String appCode) { + DataSecurity dataSecurity = getAppConfig(appCode).getDataSecurity(); + switch (dataSecurity.getAlgorithm()) { + case "AES": + return MainSecurity.aesDecrypt(body, dataSecurity.getPrivateKey()); + case "RSA": + return MainSecurity.rsaDecrypt(body, dataSecurity.getPrivateKey()); + default: + break; + } + log.info(" appCode:{}, decrypt key config is error.", appCode); + throw new HttpException(10011); + } - public static String getApiCodeConfigCacheKey(RoutingContext rc){ - String domain = rc.request().authority().host(); - log.info("domain:{}", domain); - String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); - String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey()); - String key = appCode + ":" + apiCode; - if (StringUtils.isBlank(appCode) || StringUtils.isBlank(apiCode) - || AppConfigHandler.getAppConfig(appCode) == null - || AppConfigHandler.getApicodeConfig(key) == null) { - // 判断OPEN模式, header不传递参数, 走域名映射 - AppConfig appConfig = AppConfigHandler.getAppConfigByDomain(domain); - if(appConfig != null) { - appCode = appConfig.getAppCode(); - apiCode = domain; - rc.request().headers().add(AppConfigHandler.getAppCodeHeaderKey(), appCode); - rc.request().headers().add(AppConfigHandler.getApiCodeHeaderKey(), apiCode); - key = appCode + ":" + apiCode; - } else { - rc.fail(new HttpException(10012)); - } - } - return key; - } } diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/AppRateLimitHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/AppRateLimitHandlerImpl.java index 0f9882a..412e9bd 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/AppRateLimitHandlerImpl.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/AppRateLimitHandlerImpl.java @@ -1,6 +1,8 @@ package com.sf.vertx.handle; import com.sf.vertx.constans.RedisKeyConfig; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.ServiceException; import com.sf.vertx.pojo.SacCurrentLimiting; import io.github.resilience4j.core.functions.CheckedRunnable; @@ -20,27 +22,23 @@ public class AppRateLimitHandlerImpl implements AppRateLimitHandler { @Override public void handle(RoutingContext rc) { + log.info("Enter AppRateLimitHandlerImpl.handle()"); String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); SacCurrentLimiting currentLimiting = AppConfigHandler.getGlobalAppCurrentLimitingConfig(appCode); if (currentLimiting != null) { String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + ":" + appCode; RateLimiter rateLimiter = currentLimiting.getRegistry().rateLimiter(key); - CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, () -> { - rc.next(); - return; - }); + CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, rc::next); try { restrictedCall.run(); } catch (Throwable t) { //t.printStackTrace(); log.info("app ratelimit:{}", key); - rc.fail(new HttpException(10015, currentLimiting.getStrategy().getDefaultResponse())); - return; + rc.fail(new ServiceException(GatewayError.REQUEST_URL_RESTRICTED_BY_FLOW, currentLimiting.getStrategy().getDefaultResponse())); } } else { rc.next(); - return; } } } diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java index c6dfb3a..e88f59f 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java @@ -5,10 +5,6 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.commons.lang3.StringUtils; - -import com.sf.vertx.constans.SacErrorCode; - /* * Copyright 2014 Red Hat, Inc. * @@ -25,6 +21,10 @@ import com.sf.vertx.constans.SacErrorCode; * You may elect to redistribute this code under either of these licenses. */ +import com.sf.vertx.api.pojo.ApiConfig; +import com.sf.vertx.api.pojo.AppConfig; +import com.sf.vertx.enums.RequestMethod; +import com.sf.vertx.utils.AppUtils; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.http.HttpHeaderValues; import io.vertx.core.Future; @@ -39,10 +39,11 @@ import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.ext.web.FileUpload; import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.HttpException; import io.vertx.ext.web.impl.FileUploadImpl; import io.vertx.ext.web.impl.RoutingContextInternal; +import static com.sf.vertx.constans.SACConstants.*; + /** * @author Tim Fox */ @@ -77,94 +78,82 @@ public class BodyHandlerImpl implements BodyHandler { @Override public void handle(RoutingContext context) { - // TODO 改造了这个地方 - final HttpServerRequest request = context.request(); - final HttpServerResponse response = context.response(); - String appCode = context.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); - String apiCode = context.request().headers().get(AppConfigHandler.getApiCodeHeaderKey()); - String contentType = context.request().headers().get(HttpHeaders.CONTENT_TYPE); - boolean isLoadBody = false; - try { - isLoadBody = AppConfigHandler.isAnalysisBody(appCode, apiCode, contentType); - } catch (Exception e) { - e.printStackTrace(); - context.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE)); - return; - } - if (isLoadBody) { - // =======源码流程 -// final HttpServerRequest request = context.request(); -// final HttpServerResponse response = context.response(); - // - // we need to keep state since we can be called again on reroute - if (!((RoutingContextInternal) context).seenHandler(RoutingContextInternal.BODY_HANDLER)) { - ((RoutingContextInternal) context).visitHandler(RoutingContextInternal.BODY_HANDLER); + // =======源码流程 + final HttpServerRequest request = context.request(); + final HttpServerResponse response = context.response(); + // + // we need to keep state since we can be called again on reroute + if (!((RoutingContextInternal) context).seenHandler(RoutingContextInternal.BODY_HANDLER)) { + ((RoutingContextInternal) context).visitHandler(RoutingContextInternal.BODY_HANDLER); - // Check if a request has a request body. - // A request with a body __must__ either have `transfer-encoding` - // or `content-length` headers set. - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 - final long parsedContentLength = parseContentLengthHeader(request); - // http2 never transmits a `transfer-encoding` as frames are chunks. - final boolean hasTransferEncoding = request.version() == HttpVersion.HTTP_2 - || request.headers().contains(HttpHeaders.TRANSFER_ENCODING); + // Check if a request has a request body. + // A request with a body __must__ either have `transfer-encoding` + // or `content-length` headers set. + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 + final long parsedContentLength = parseContentLengthHeader(request); + // http2 never transmits a `transfer-encoding` as frames are chunks. + final boolean hasTransferEncoding = request.version() == HttpVersion.HTTP_2 + || request.headers().contains(HttpHeaders.TRANSFER_ENCODING); - if (!hasTransferEncoding && parsedContentLength == -1) { - // there is no "body", so we can skip this handler - context.next(); - return; - } + if (!hasTransferEncoding && parsedContentLength == -1) { + // there is no "body", so we can skip this handler + context.next(); + return; + } - // before parsing the body we can already discard a bad request just by - // inspecting the content-length against - // the body limit, this will reduce load, on the server by totally skipping - // parsing the request body - if (bodyLimit != -1 && parsedContentLength != -1) { - if (parsedContentLength > bodyLimit) { - context.fail(413); - return; - } - } + // before parsing the body we can already discard a bad request just by + // inspecting the content-length against + // the body limit, this will reduce load, on the server by totally skipping + // parsing the request body + if (bodyLimit != -1 && parsedContentLength != -1) { + if (parsedContentLength > bodyLimit) { + context.fail(413); + return; + } + } - // handle expectations - // https://httpwg.org/specs/rfc7231.html#header.expect - final String expect = request.getHeader(HttpHeaders.EXPECT); - if (expect != null) { - // requirements validation - if (expect.equalsIgnoreCase("100-continue")) { - // A server that receives a 100-continue expectation in an HTTP/1.0 request MUST - // ignore that expectation. - if (request.version() != HttpVersion.HTTP_1_0) { - // signal the client to continue - response.writeContinue(); - } - } else { - // the server cannot meet the expectation, we only know about 100-continue - context.fail(417); - return; - } - } - - final BHandler handler = new BHandler(context, isPreallocateBodyBuffer ? parsedContentLength : -1); - boolean ended = request.isEnded(); - if (!ended) { - request - // resume the request (if paused) - .handler(handler).endHandler(handler::end).resume(); - } - } else { - // on reroute we need to re-merge the form params if that was desired - if (mergeFormAttributes && request.isExpectMultipart()) { - request.params().addAll(request.formAttributes()); - } + // handle expectations + // https://httpwg.org/specs/rfc7231.html#header.expect + final String expect = request.getHeader(HttpHeaders.EXPECT); + if (expect != null) { + // requirements validation + if (expect.equalsIgnoreCase("100-continue")) { + // A server that receives a 100-continue expectation in an HTTP/1.0 request MUST + // ignore that expectation. + if (request.version() != HttpVersion.HTTP_1_0) { + // signal the client to continue + response.writeContinue(); + } + } else { + // the server cannot meet the expectation, we only know about 100-continue + context.fail(417); + return; + } + } + // TODO 改造了这个地方 在真正解析body之前验证是否需要继续解析 + AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(context); + ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(context); + String apiServiceType = context.get(API_SERVICE_TYPE); + if (!AppUtils.isAnalysisBody(appConfig,apiConfig,apiServiceType)){ context.next(); + return; } - } else { - // 非加解密不处理 - context.next(); - return; - } + + final BHandler handler = new BHandler(context, isPreallocateBodyBuffer ? parsedContentLength : -1); + boolean ended = request.isEnded(); + if (!ended) { + request + // resume the request (if paused) + .handler(handler).endHandler(handler::end).resume(); + } + } else { + // on reroute we need to re-merge the form params if that was desired + if (mergeFormAttributes && request.isExpectMultipart()) { + request.params().addAll(request.formAttributes()); + } + context.next(); + } } @Override diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/OpenParameterCheckHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/OpenParameterCheckHandlerImpl.java new file mode 100644 index 0000000..fcdab2d --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/OpenParameterCheckHandlerImpl.java @@ -0,0 +1,50 @@ +package com.sf.vertx.handle; + +import com.sf.vertx.api.pojo.ApiConfig; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.ServiceException; + +import com.sf.vertx.api.pojo.AppConfig; + +import com.sf.vertx.utils.AppUtils; +import io.vertx.ext.web.RoutingContext; +import lombok.extern.slf4j.Slf4j; + +import static com.sf.vertx.constans.SACConstants.*; + +@Slf4j +public class OpenParameterCheckHandlerImpl implements ParameterCheckHandler { + + @Override + public void handle(RoutingContext rc) { + try { + log.info("Enter OPEN Route"); + // 判断OPEN模式, header不传递参数, 走域名映射 + String domain = rc.request().authority().host(); + log.info("request domain:{}", domain); + AppConfig appConfig = AppConfigHandler.getAppConfigByDomain(domain); + if (appConfig == null) { + rc.fail(new ServiceException(GatewayError.APP_SERVICE_NOT_FOUND)); + return; + } + String apiCacheKey = appConfig.getAppCode() + CACHE_KEY_CONNECTOR + domain; + ApiConfig apiConfig = AppConfigHandler.getApicodeConfig(apiCacheKey); + if (apiConfig == null) { + rc.fail(new ServiceException(GatewayError.API_SERVICE_NOT_FOUND)); + return; + } + // 设置应用配置、接口配置到上下文 + AppUtils.setAppConfigToRoutingContext(appConfig,rc); + AppUtils.setApiConfigIntoRoutingContext(apiConfig,rc); + rc.put(API_SERVICE_TYPE,AppConfigHandler.getServiceTypeOpen(apiCacheKey)); + // 将appcode和apicode设置到请求头,兼容原有逻辑 + rc.request().headers().add(AppConfigHandler.getAppCodeHeaderKey(), appConfig.getAppCode()); + rc.request().headers().add(AppConfigHandler.getApiCodeHeaderKey(), apiConfig.getApiCode()); + } catch (Exception e) { + log.error("OpenParameterCheckHandlerImpl Error:",e); + rc.fail(new ServiceException(GatewayError.DEFAULT_SERVICE_ERROR)); + return; + } + rc.next(); + } +} diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandler.java b/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandler.java index ce62ab5..e1d61e9 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandler.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandler.java @@ -1,19 +1,29 @@ package com.sf.vertx.handle; +import com.sf.vertx.enums.GatewayServiceType; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.ServiceException; import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.Handler; import io.vertx.ext.web.RoutingContext; /*** * 入口参数校验 - * + * * @author xy * */ @VertxGen public interface ParameterCheckHandler extends Handler { - static ParameterCheckHandler create() { - return new ParameterCheckHandlerImpl(); - } + static ParameterCheckHandler create(GatewayServiceType serviceType) { + switch (serviceType) { + case SAC: + return new SACParameterCheckHandlerImpl(); + case OPEN: + return new OpenParameterCheckHandlerImpl(); + default: + throw new ServiceException(GatewayError.INTERNAL_SERVER_ERROR); + } + } } diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandlerImpl.java deleted file mode 100644 index d5d0396..0000000 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/ParameterCheckHandlerImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.sf.vertx.handle; - -import com.sf.vertx.api.pojo.MockResponse; -import io.vertx.ext.web.RequestBody; -import org.apache.commons.lang3.StringUtils; - -import com.sf.vertx.api.pojo.AppConfig; -import com.sf.vertx.constans.SacErrorCode; - -import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.HttpException; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class ParameterCheckHandlerImpl implements ParameterCheckHandler { - - @Override - public void handle(RoutingContext rc) { - try { - String domain = rc.request().authority().host(); - log.info("domain:{}", domain); - String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); - String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey()); - String key = appCode + ":" + apiCode; - if (StringUtils.isBlank(appCode) || StringUtils.isBlank(apiCode) - || AppConfigHandler.getAppConfig(appCode) == null - || AppConfigHandler.getApicodeConfig(key) == null) { - // 判断OPEN模式, header不传递参数, 走域名映射 - AppConfig appConfig = AppConfigHandler.getAppConfigByDomain(domain); - if(appConfig != null) { - appCode = appConfig.getAppCode(); - apiCode = domain; - rc.request().headers().add(AppConfigHandler.getAppCodeHeaderKey(), appCode); - rc.request().headers().add(AppConfigHandler.getApiCodeHeaderKey(), apiCode); - key = appCode + ":" + apiCode; - } else { - rc.fail(new HttpException(10012)); - return; - } - } - - if(AppConfigHandler.isDisabledAppcode(apiCode)) { - rc.fail(new HttpException(10001)); - return; - } - - // 通过请求模式来区分 - String uri = rc.request().uri(); - String httpMethod = rc.request().method().name(); - if(AppConfigHandler.isServiceTypeOpen(key) && AppConfigHandler.isApicodeUri(key, uri, httpMethod) == false) { - rc.fail(new HttpException(10018)); - return; - } - - } catch (Exception e) { - e.printStackTrace(); - rc.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE)); - return; - } - - - rc.next(); - return; - } -} diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/RestfulFailureHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/RestfulFailureHandlerImpl.java index d6cd4a7..c8889d8 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/RestfulFailureHandlerImpl.java +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/RestfulFailureHandlerImpl.java @@ -1,57 +1,66 @@ package com.sf.vertx.handle; -import io.vertx.core.buffer.Buffer; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.MockException; +import com.sf.vertx.exception.ServiceException; +import com.sf.vertx.utils.AppUtils; import org.apache.commons.lang3.StringUtils; -import com.sf.vertx.constans.SacErrorCode; - -import io.vertx.core.http.HttpHeaders; import io.vertx.core.json.JsonObject; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.HttpException; import lombok.extern.slf4j.Slf4j; + @Slf4j public class RestfulFailureHandlerImpl implements RestfulFailureHandler { @Override public void handle(RoutingContext frc) { int statusCode = 500; - JsonObject errorJson = null; - Integer sc = SacErrorCode.DEFAULT_ERROR_CODE; + JsonObject errorJson; + // 网关的业务码 + int gatewayServiceCode = GatewayError.DEFAULT_SERVICE_ERROR.getCode(); try { Throwable failure = frc.failure(); log.info("failure:", failure); if (failure instanceof HttpException) { HttpException httpException = (HttpException) failure; - sc = httpException.getStatusCode(); - if (StringUtils.isNoneBlank(httpException.getPayload())) { - errorJson = new JsonObject(httpException.getPayload()); - } else { - errorJson = SacErrorCode.returnErrorMsg(httpException.getStatusCode()); + gatewayServiceCode = httpException.getStatusCode(); + errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.getByCode(statusCode)); + if (StringUtils.isNotBlank(httpException.getPayload())){ + errorJson.put("msg",httpException.getPayload()); } } else if (failure instanceof MockException) { - MockException httpException = (MockException) failure; - sc = httpException.getStatusCode(); - statusCode = httpException.getStatusCode(); - if (StringUtils.isNoneBlank(httpException.getPayload())) { - errorJson = new JsonObject(httpException.getPayload()); - } else { - errorJson = SacErrorCode.returnErrorMsg(httpException.getStatusCode()); + MockException mockException = (MockException) failure; + gatewayServiceCode = mockException.getStatusCode(); + statusCode = mockException.getStatusCode(); + errorJson = new JsonObject(mockException.getPayload()); + }else if (failure instanceof ServiceException) { + ServiceException serviceException = (ServiceException) failure; + gatewayServiceCode = serviceException.getStatusCode(); + // 业务异常,为网关业务错误,响应码设置为500, + GatewayError gatewayError = GatewayError.getByCode(serviceException.getStatusCode()); + // 如果是被限流或熔断,直接返回限流或熔断响应 + if (GatewayError.REQUEST_URL_RESTRICTED_BY_FLOW.equals(gatewayError) + || GatewayError.REQUEST_URL_IS_BROKEN.equals(gatewayError)){ + errorJson = new JsonObject(serviceException.getPayload()); + }else { + errorJson = AppUtils.getResponseJsonByGatewayError(gatewayError); } } else { - errorJson = SacErrorCode.returnErrorMsg(SacErrorCode.DEFAULT_ERROR_CODE); + errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.getByCode(statusCode)); } } catch (Exception e) { - e.printStackTrace(); - errorJson = SacErrorCode.returnErrorMsg(SacErrorCode.DEFAULT_ERROR_CODE); + log.error("RestfulFailureHandlerImpl.handle Error:",e); + errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR); } - frc.response().setChunked(true).setStatusCode(statusCode).putHeader("Content-Type", "application/json") - .putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(sc)) + .putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(gatewayServiceCode)) .end(errorJson.toBuffer()); - return; } + + } diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/SACParameterCheckHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/SACParameterCheckHandlerImpl.java new file mode 100644 index 0000000..b371815 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/SACParameterCheckHandlerImpl.java @@ -0,0 +1,50 @@ +package com.sf.vertx.handle; + +import com.sf.vertx.api.pojo.ApiConfig; +import com.sf.vertx.api.pojo.AppConfig; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.exception.ServiceException; +import com.sf.vertx.utils.AppUtils; +import io.vertx.ext.web.RoutingContext; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import static com.sf.vertx.constans.SACConstants.*; + +@Slf4j +public class SACParameterCheckHandlerImpl implements ParameterCheckHandler { + + @Override + public void handle(RoutingContext rc) { + try { + log.info("Enter SAC Route"); + // SAC规范要求Header必须要同时包含appCode和apiCode + String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey()); + String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey()); + if (StringUtils.isBlank(appCode) || StringUtils.isBlank(apiCode)) { + rc.fail(new ServiceException(GatewayError.PARAMETER_TRANSFER_ERROR)); + return; + } + AppConfig appConfig = AppConfigHandler.getAppConfig(appCode); + if (appConfig == null) { + rc.fail(new ServiceException(GatewayError.APP_SERVICE_NOT_FOUND)); + return; + } + String apiCacheKey = appConfig.getAppCode() + CACHE_KEY_CONNECTOR + apiCode; + ApiConfig apiConfig = AppConfigHandler.getApicodeConfig(apiCacheKey); + if (apiConfig == null) { + rc.fail(new ServiceException(GatewayError.API_SERVICE_NOT_FOUND)); + return; + } + // 设置应用配置、接口配置到上下文 + AppUtils.setAppConfigToRoutingContext(appConfig,rc); + AppUtils.setApiConfigIntoRoutingContext(apiConfig,rc); + rc.put(API_SERVICE_TYPE,AppConfigHandler.getServiceTypeOpen(apiCacheKey)); + } catch (Exception e) { + log.error("SACParameterCheckHandlerImpl Error:",e); + rc.fail(new ServiceException(GatewayError.DEFAULT_SERVICE_ERROR)); + return; + } + rc.next(); + } +} diff --git a/sf-vertx/src/main/java/com/sf/vertx/security/MainSecurity.java b/sf-vertx/src/main/java/com/sf/vertx/security/MainSecurity.java index affb33c..5068206 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/security/MainSecurity.java +++ b/sf-vertx/src/main/java/com/sf/vertx/security/MainSecurity.java @@ -17,7 +17,7 @@ public class MainSecurity { */ public static String rsaEncrypt(String content, String pubKey) { try { - return RSAUtil.encrypt1(content, pubKey); + return RSAUtil.encrypt(content, pubKey); } catch (Exception e) { LOGGER.info("RSA加密失败"); e.printStackTrace(); @@ -27,7 +27,7 @@ public class MainSecurity { public static String rsaDecrypt(String content, String priKey) { try { - return RSAUtil.decrypt1(content, priKey); + return RSAUtil.decrypt(content, priKey); } catch (Exception e) { LOGGER.info("RSA解密失败"); e.printStackTrace(); diff --git a/sf-vertx/src/main/java/com/sf/vertx/security/RSAUtil.java b/sf-vertx/src/main/java/com/sf/vertx/security/RSAUtil.java index 85a3f49..44b1059 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/security/RSAUtil.java +++ b/sf-vertx/src/main/java/com/sf/vertx/security/RSAUtil.java @@ -1,173 +1,148 @@ package com.sf.vertx.security; -import java.security.Key; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; +import java.security.SecureRandom; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; -import java.util.Base64; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.ArrayUtils; + import lombok.extern.slf4j.Slf4j; @Slf4j public class RSAUtil { - public static final String KEY_ALGORITHM = "RSA"; - - private static final String PUBLIC_KEY = "RSAPublicKey"; - - private static final String PRIVATE_KEY = "RSAPrivateKey"; - - // 1024 bits 的 RSA 密钥对,最大加密明文大小 + // RSA最大加密明文大小 private static final int MAX_ENCRYPT_BLOCK = 117; - // 1024 bits 的 RSA 密钥对,最大解密密文大小 + // RSA最大解密密文大小 private static final int MAX_DECRYPT_BLOCK = 128; - // 生成密钥对 - public static Map initKey(int keysize) throws Exception { - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); - // 设置密钥对的 bit 数,越大越安全 - keyPairGen.initialize(keysize); + private RSAUtil() { + } + + /** + * 获取公钥和私钥对,key为公钥,value为私钥 + * + * @return + * @throws NoSuchAlgorithmException + */ + public static Map genKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); + keyPairGen.initialize(1024, new SecureRandom()); KeyPair keyPair = keyPairGen.generateKeyPair(); - - // 获取公钥 - RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); - // 获取私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); - Map keyMap = new HashMap<>(2); - keyMap.put(PUBLIC_KEY, publicKey); - keyMap.put(PRIVATE_KEY, privateKey); - return keyMap; - } + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + String publicKeyString = null; + String privateKeyString = null; - // 获取公钥字符串 - public static String getPublicKeyStr(Map keyMap) { - // 获得 map 中的公钥对象,转为 key 对象 - Key key = (Key) keyMap.get(PUBLIC_KEY); - // 编码返回字符串 - return encryptBASE64(key.getEncoded()); - } - - // 获取私钥字符串 - public static String getPrivateKeyStr(Map keyMap) { - // 获得 map 中的私钥对象,转为 key 对象 - Key key = (Key) keyMap.get(PRIVATE_KEY); - // 编码返回字符串 - return encryptBASE64(key.getEncoded()); - } - - // 获取公钥 - public static PublicKey getPublicKey(String publicKeyString) throws NoSuchAlgorithmException, InvalidKeySpecException { - byte[] publicKeyByte = Base64.getDecoder().decode(publicKeyString); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByte); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - return keyFactory.generatePublic(keySpec); - } - - // 获取私钥 - public static PrivateKey getPrivateKey(String privateKeyString) throws Exception { - byte[] privateKeyByte = Base64.getDecoder().decode(privateKeyString); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyByte); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - return keyFactory.generatePrivate(keySpec); - } - - /** - * BASE64 编码返回加密字符串 - * - * @param key 需要编码的字节数组 - * @return 编码后的字符串 - */ - public static String encryptBASE64(byte[] key) { - return new String(Base64.getEncoder().encode(key)); - } - - /** - * BASE64 解码,返回字节数组 - * - * @param key 待解码的字符串 - * @return 解码后的字节数组 - */ - public static byte[] decryptBASE64(String key) { - return Base64.getDecoder().decode(key); - } - - /** - * 公钥加密 - * - * @param text 待加密的明文字符串 - * @param publicKeyStr 公钥 - * @return 加密后的密文 - */ - public static String encrypt1(String text, String publicKeyStr) { try { - log.info("明文字符串为:[{}]", text); - Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKeyStr)); - byte[] tempBytes = cipher.doFinal(text.getBytes("UTF-8")); - return Base64.getEncoder().encodeToString(tempBytes); - } catch (Exception e) { - throw new RuntimeException("加密字符串[" + text + "]时遇到异常", e); + publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()), "UTF-8"); + privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()), "UTF-8"); + } catch (UnsupportedEncodingException var7) { + var7.printStackTrace(); } + + Map keyPairMap = new HashMap<>(); + keyPairMap.put("publicKey", publicKeyString); + keyPairMap.put("privateKey", privateKeyString); + return keyPairMap; + } + + public static String encrypt(String str, String publicKey) throws Exception { + byte[] decoded = Base64.decodeBase64(publicKey); + RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA") + .generatePublic(new X509EncodedKeySpec(decoded)); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(1, pubKey); + // 分段加密 + // URLEncoder编码解决中文乱码问题 + byte[] data = URLEncoder.encode(str, "UTF-8").getBytes("UTF-8"); + // 加密时超过117字节就报错。为此采用分段加密的办法来加密 + byte[] enBytes = null; + for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) { + // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码 + byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK)); + enBytes = ArrayUtils.addAll(enBytes, doFinal); + } + return Base64.encodeBase64String(enBytes); } /** - * 私钥解密 + * 公钥分段解密 * - * @param secretText 待解密的密文字符串 - * @param privateKeyStr 私钥 - * @return 解密后的明文 + * @param str + * @param privateKey + * @return + * @throws Exception */ - public static String decrypt1(String secretText, String privateKeyStr) { - try { - // 生成私钥 - Cipher cipher = Cipher.getInstance(KEY_ALGORITHM); - cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr)); - // 密文解码 - byte[] secretTextDecoded = Base64.getDecoder().decode(secretText.getBytes("UTF-8")); - byte[] tempBytes = cipher.doFinal(secretTextDecoded); - return new String(tempBytes); - } catch (Exception e) { - throw new RuntimeException("解密字符串[" + secretText + "]时遇到异常", e); + public static String decrypt(String str, String privateKey) throws Exception { + // 获取公钥 + byte[] decoded = Base64.decodeBase64(privateKey); + RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA") + .generatePrivate(new PKCS8EncodedKeySpec(decoded)); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(2, priKey); + byte[] data = Base64.decodeBase64(str.getBytes("UTF-8")); + + // 返回UTF-8编码的解密信息 + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * 128; } + byte[] decryptedData = out.toByteArray(); + out.close(); + return URLDecoder.decode(new String(decryptedData, "UTF-8"), "UTF-8"); } public static void main(String[] args) throws Exception { - Map keyMap; - String cipherText; - // 原始明文 - String content = "{\"data\":{\"a\":1,\"b\":\"dd\"},\"divideHttpUrl\":{\"company\":{\"aesKey\":\"dadddsdfadfadsfa33323223\"}}}\n" - + ""; + Map keyMap = genKeyPair(); + String publicKey = keyMap.get("publicKey"); + String privateKey = keyMap.get("privateKey"); + privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIBjjfp2vkdIDzw9vTzei9S1Gg8KLfPWNYfESwgqGvPY/ps3rIfgPH4na3qy957AY/zHExjaPGbbBRBRPV3xg1vrccr0oZLPiC5n7+4Z5TR6wYiPOn3osSjCweUJ7LttOTAr8sqvaHlrDbpZD+ZoOiB0TEWWD9TvI4pK0sVs7JYRAgMBAAECgYAJ08T3c80Y/u2mnGmunfC5U3LnDY4KpN30Uky1d2aYfWawqhRnUp1CwUDvc4EzajHFFJZUP8khjNhwgS1nsk+t9fnz/GJSS2ZYIOn/i1WEKCJvCILuFpx9tqQM1I9EdueeW1VQgm24o6vbBTP6JzoRXN/l/dAGldluY+Y2JclVeQJBAIyZdxIo1G7qs2nbKkynQaPY/ogmn7VLTWwowri1bhWt0zzcDu3/TgLLPldWVwYUuRChyVvX3cuQB0ICwiKTB3kCQQDpxGufjUgalAZwe+RCxIDriKVvYmB/krk/escAR39Ya6Od7nHSbmdBUmc7vjLbVN3BsYWZrlxHnGelEetebqVZAkBJrxvR7of2YRYJwgxXA8jIv64VWHiWoJJAvtPdzWeWAPUVjhZc8FHH8RAI4XzV+QJMDx3h/i2Ew0SqeZuYVwmxAkBh2T3TQyfzOBKZ8sHQ0L/F1ySoQt1xiNDRqWqyyzqaoDOUX8J0+pFt3jgn4a0X8aYA9XWepkUqFGWtyppipJ3BAkEAigeRnLS/J4Z6inWy4XJfFrggYvtQvWQnGfjHNQijm7+c8Nb+gs2EjbkEHg13yFUpBa3sVPN+aOhP2R41t4EywA=="; + publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCAY436dr5HSA88Pb083ovUtRoPCi3z1jWHxEsIKhrz2P6bN6yH4Dx+J2t6sveewGP8xxMY2jxm2wUQUT1d8YNb63HK9KGSz4guZ+/uGeU0esGIjzp96LEowsHlCey7bTkwK/LKr2h5aw26WQ/maDogdExFlg/U7yOKStLFbOyWEQIDAQAB"; + log.info("publicKey = " + publicKey); + log.info("privateKey = " + privateKey); + String originValue = "{\n" + + " \"data\": \"1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说\",\n" + + " \"data1\": \"11是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说\",\n" + + " \"data2\": \"11是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说1是发送到发送到发哈都是开发计划署的环境封建社会的大是大非上对方哈史蒂芬霍金啊说\"\n" + + "}"; + // 加密前:原数据123456,测试一下 + System.out.println("加密前:" + originValue); - // 生成密钥对 - keyMap = initKey(1024); - String publicKey = getPublicKeyStr(keyMap); - log.info("公钥:[{}],长度:[{}]", publicKey, publicKey.length()); - String privateKey = getPrivateKeyStr(keyMap); - log.info("私钥:[{}],长度:[{}]", privateKey, privateKey.length()); - - publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuIBxYMYWgIau1BKjTpM/9JhIHRnO4QoaiOrVJk+OFWAJFpFrZoDj3JYQF4ywD8uWOx28EBf+g+U8UIE0pS93IEvm/O47VOwSqSvc5tpXmrxHTVgHSqcXqXkm4+q64c525N5bhUbReXI/CSKU62EH7MWapjHD7vPKGVCwjg8RHCQIDAQAB"; - privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK4gHFgxhaAhq7UEqNOkz/0mEgdGc7hChqI6tUmT44VYAkWkWtmgOPclhAXjLAPy5Y7HbwQF/6D5TxQgTSlL3cgS+b87jtU7BKpK9zm2leavEdNWAdKpxepeSbj6rrhznbk3luFRtF5cj8JIpTrYQfsxZqmMcPu88oZULCODxEcJAgMBAAECgYAA+yU4/xgPny6Sm97ChoD80k6pzpubAP6URKJMXSQcFBaxtPnZivfU005qNY7qGApXBj69Otw8pC8YvsP+KEsHAmPS78AmzAlh6rojkwl+A1F3a23CyxWKDik/HWsXJ1WSl5ljw/+rW6/38YVfPEKZSOWOTwfYxFWI553j05CVKQJBALkhR60uwGaGpV1ApHwcuaSN6rVQ46D67qmkKG3rLkZJyDziFBabl685UCKiDXqwRoX3UWI0FDqDUhSqoBo/LJUCQQDwyGJiUIAI8bTj6q4+1LxeHMlcJWXaRvOK0BocH+6KpybMKf0R478ziYTtNiaSY45syaDQKofVyE8kzTN37J+lAkAs9EHdcd7ShpudG1dVs/v4U2XNBYlgy84sb2pJ1rPz6XKwJg3Ot5WLvRUSc9tmEWvul/GxMQhAdSb3Ub9y4ChJAkEA7Wj3MO8kvyzr6gpcklEaBkWl+TharBVnTwiPpgmKH6ZeZ9JC2B/SR9OhgG7zK0YEiZlo+bflxVHDT4sQ438pjQJBALIQpdg34BQwWMTx4MxP0Wji51JDZM7h24SReb0RktfsY9s6ZU6mbu3oJNnInD+GQkRJkYNkK4DPrczIxnMpddE="; - // 加密 - cipherText = encrypt1(content, publicKey); - log.info("加密后的密文:[{}],长度:[{}]", cipherText, cipherText.length()); - - // 解密 - cipherText = "DaztB3mXoFSZ6wtu4K1mpnFryyeBckeIa0RoLpejCltFj9UZWP3FwTw50SeFlK5dqWE/J0jQUBSRZDJ8qZ2/vnuNqaUxn+JcaUTqlShYV8wbYoqr8tCSFJ0PoHLMdkjS1xFcADqsgRTSsB67dd4qth3K5vU1iQQR30QHPv3I6nY="; - String plainText = decrypt1(cipherText, privateKey); - log.info("解密后明文:[{}]", plainText); + String encrypt = encrypt(originValue, publicKey); + log.info("加密后:" + encrypt); + encrypt = "HxlTvNpgMBj3tcqcXWQc1SFvn8c4nv0HYBlvuVy07BUa1ynQXhhNoT9o7iX5/edJ9xLGITsWRMUfQvuND9ttsyQS44oRmbkRBAdLZQOxaS4hkMDGleWMZII0VgQbULeOd7SEq5Ba2UU7TDySg0VLRgRRgnxt2qUig9Gx/3quQY19Ts9Wu+NBRi1JvCQD5bKi+9BW+jMKIjZ5hx2MwsVVIQDkoQKLcRTV6lejrXdPP7fFo6rG3/OULM7+U/rw2EoC+F+2NRIoEIQj2jclmM8kqAspNJH2NmP/0lsgjay7/nK2nU1Gz/zeQsSVgJmggTUxTImKk5eoqckuNdPD2mwyRQ=="; + String decrypt = decrypt(encrypt, privateKey); + log.info("解密后:" + decrypt); } } + diff --git a/sf-vertx/src/main/java/com/sf/vertx/utils/AppUtils.java b/sf-vertx/src/main/java/com/sf/vertx/utils/AppUtils.java new file mode 100644 index 0000000..0968313 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/utils/AppUtils.java @@ -0,0 +1,255 @@ +package com.sf.vertx.utils; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.NumberUtil; +import com.sf.vertx.api.pojo.*; +import com.sf.vertx.enums.GatewayError; +import com.sf.vertx.enums.GatewayServiceType; +import com.sf.vertx.enums.MatchType; +import com.sf.vertx.enums.RequestMethod; +import com.sf.vertx.handle.AppConfigHandler; +import io.vertx.circuitbreaker.CircuitBreaker; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.RoutingContext; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.util.List; + +import static com.sf.vertx.constans.SACConstants.*; + +/** + * 功能描述: + * + * @author a_kun + * @date 2024/5/24 12:30 + */ +@Slf4j +@UtilityClass +public class AppUtils { + + /** + * 将AppConfig设置到上下文中 + * 配合getAppConfigFromRoutingContext(RoutingContext rc)使用 + * @param appConfig + * @param rc + */ + public static void setAppConfigToRoutingContext(AppConfig appConfig, RoutingContext rc) { + rc.put(APP_CONFIG,appConfig); + } + + /** + * 从路由上下文获取AppConfig + * @param rc + * @return AppConfig + */ + public static AppConfig getAppConfigFromRoutingContext(RoutingContext rc) { + return rc.get(APP_CONFIG); + } + + /** + * 将AppConfig设置到上下文中 + * 配合getApiConfigFromRoutingContext(RoutingContext rc)使用 + * @param apiConfig + * @param rc + */ + public static void setApiConfigIntoRoutingContext(ApiConfig apiConfig, RoutingContext rc) { + rc.put(API_CONFIG,apiConfig); + } + + /** + * 从路由上下文获取ApiConfig + * @param rc + * @return ApiConfig + */ + public static ApiConfig getApiConfigFromRoutingContext(RoutingContext rc) { + return rc.get(API_CONFIG); + } + + public static boolean isEnableMockApi(ApiConfig apiConfig) { + if (apiConfig != null) { + return apiConfig.getMockDefaultHttpStatus() != null; + } + return false; + } + + /** + * 判断API服务类型是否是SAC规范服务类型 + * + * @param apiServiceType + * @return + */ + public static boolean isSACServiceType(String apiServiceType) { + return GatewayServiceType.SAC.getCode().equals(apiServiceType); + } + + public static boolean isEnableDataSecurity(AppConfig appConfig) { + return appConfig != null && appConfig.getDataSecurity() != null; + } + + public static MockResponse mock(RoutingContext rc) { + AppConfig appConfig = getAppConfigFromRoutingContext(rc); + ApiConfig apiConfig = getApiConfigFromRoutingContext(rc); + String apiServiceType = rc.get(API_SERVICE_TYPE); + if (AppUtils.isEnableMockApi(apiConfig)) { + // 如果是sac服务,query和body参数都从body中取 + Integer httpStatus = apiConfig.getMockDefaultHttpStatus(); + String mockResponse = apiConfig.getMockDefaultResponse(); + List mockExpectations = apiConfig.getMockExpectations(); + if (mockExpectations != null && !mockExpectations.isEmpty()) { + String bodyStr = rc.body().asString(); + if (AppUtils.isEnableDataSecurity(appConfig)) { + bodyStr = AppConfigHandler.bodyDecrypt(bodyStr, appConfig.getAppCode()); + } + JsonObject jsonBody = new JsonObject(bodyStr); + for (MockExpectation mockExpectation : mockExpectations) { + // 匹配条件需要全部匹配成功 + boolean matchSuccess = true; + for (MockMatchCondition matchCondition : mockExpectation.getMatchConditions()) { + if (!matchSuccess) { + break; + } + MatchType matchType = MatchType.getByCode(matchCondition.getMatchType()); + if (matchType == null) { + matchSuccess = false; + break; + } + String parameterPosition = matchCondition.getParameterPosition(); + String parameterKey = matchCondition.getParameterKey(); + List parameterValue = matchCondition.getParameterValue(); + String requestParameterValue = getRequestParameterValue(AppUtils.isSACServiceType(apiServiceType), parameterPosition, parameterKey, rc.request(), jsonBody); + if (!MatchType.IS_NULL.equals(matchType) && !MatchType.NOT_NULL.equals(matchType)) { + // 需要值而没有设置值,直接匹配失败 + if (CollectionUtil.isEmpty(parameterValue) || requestParameterValue == null) { + matchSuccess = false; + break; + } + } + + switch (matchType) { + case EQ: + matchSuccess = parameterValue.get(0).equals(requestParameterValue); + break; + case NOT_EQ: + matchSuccess = !parameterValue.get(0).equals(requestParameterValue); + break; + case GT: + if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { + matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) > 0; + } else { + matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) > 0; + } + break; + case GE: + if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { + matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) >= 0; + } else { + matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) >= 0; + } + break; + case LT: + if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { + matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) < 0; + } else { + matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) < 0; + } + break; + case LE: + if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) { + matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) <= 0; + } else { + matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) <= 0; + } + break; + case IN: + matchSuccess = parameterValue.contains(requestParameterValue); + break; + case NOT_IN: + matchSuccess = !parameterValue.contains(requestParameterValue); + break; + case IS_NULL: + matchSuccess = requestParameterValue == null; + break; + case NOT_NULL: + matchSuccess = requestParameterValue != null; + break; + default: + break; + } + + } + if (matchSuccess) { + httpStatus = mockExpectation.getHttpStatus(); + mockResponse = mockExpectation.getMockResponse(); + break; + } + } + } + return new MockResponse(httpStatus, mockResponse); + } + return null; + } + + private static String getRequestParameterValue(Boolean isServiceTypeSac, String parameterPosition, String parameterKey, HttpServerRequest request, JsonObject jsonBody) { + switch (parameterPosition) { + case "query": + if (isServiceTypeSac) { + return jsonBody.getString(parameterKey); + } + return request.getParam(parameterKey); + case "header": + return request.getHeader(parameterKey); + case "body": + return jsonBody.getString(parameterKey); + default: + break; + } + return null; + } + + public static String getResponseMsgByGatewayError(GatewayError gatewayError) { + if (gatewayError != null) { + return gatewayError.getReasonPhrase(); + } + return getResponseMsgByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR); + } + + public static JsonObject getResponseJsonByGatewayError(GatewayError gatewayError) { + if (gatewayError != null) { + JsonObject jsonObject = new JsonObject(); + jsonObject.put("code",gatewayError.getCode()); + jsonObject.put("msg",gatewayError.getReasonPhrase()); + return jsonObject; + } + return getResponseJsonByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR); + } + + public static boolean isAnalysisBody(AppConfig appConfig, ApiConfig apiConfig,String apiServiceType) { + // 不是Mock(是mock模式的话,存在body就解析。) + if (AppUtils.isEnableMockApi(apiConfig)) { + return true; + } + // SAC模式,实际API请求方式GET,DELETE,HEAD请求需要解析body,可能需要二次处理。(SAC模式请求方式参数统一使用body传递) + // SAC模式,如果是POST或者PUT,并且没有设置数据加密则跳过 + if (AppUtils.isSACServiceType(apiServiceType)) { + RequestMethod requestMethod = RequestMethod.getByCode(apiConfig.getMethod()); + if (RequestMethod.GET.equals(requestMethod) + || RequestMethod.DELETE.equals(requestMethod) + || RequestMethod.HEAD.equals(requestMethod)) { + return true; + } + String keyCircuitBreaker = appConfig.getAppCode() + ":" + apiConfig.getApiCode() + ":" + "CIRCUIT_BREAKER"; + CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker); + boolean isDataSecurity = AppUtils.isEnableDataSecurity(appConfig); + // 文件上传不走加解密 + return (isDataSecurity || circuitBreaker != null); + }else { + // 未启用Mock,OPEN模式都不会解析body + return false; + } + + } +} diff --git a/sf-vertx/src/main/java/io/vertx/httpproxy/impl/ReverseProxy.java b/sf-vertx/src/main/java/io/vertx/httpproxy/impl/ReverseProxy.java index c1df706..2a71180 100644 --- a/sf-vertx/src/main/java/io/vertx/httpproxy/impl/ReverseProxy.java +++ b/sf-vertx/src/main/java/io/vertx/httpproxy/impl/ReverseProxy.java @@ -18,10 +18,13 @@ import java.util.Map; import java.util.function.BiFunction; import cn.hutool.core.util.StrUtil; +import com.sf.vertx.api.pojo.ApiConfig; +import com.sf.vertx.api.pojo.AppConfig; +import com.sf.vertx.enums.GatewayError; import com.sf.vertx.enums.RequestMethod; +import com.sf.vertx.utils.AppUtils; import org.apache.commons.lang3.StringUtils; -import com.sf.vertx.constans.SacErrorCode; import com.sf.vertx.handle.AppConfigHandler; import com.sf.vertx.utils.ProxyTool; @@ -57,6 +60,7 @@ import io.vertx.httpproxy.cache.CacheOptions; import io.vertx.httpproxy.spi.cache.Cache; import lombok.extern.slf4j.Slf4j; +import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE; import static org.apache.commons.lang3.StringUtils.EMPTY; @Slf4j @@ -181,7 +185,7 @@ public class ReverseProxy implements HttpProxy { * @param sc */ private void end(ProxyRequest proxyRequest, int sc) { - JsonObject json = SacErrorCode.returnErrorMsg(sc); + JsonObject json = AppUtils.getResponseJsonByGatewayError(GatewayError.getByCode(sc)); proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json") .putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(sc)) .putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(json.size())).setBody(Body.body(json.toBuffer())) @@ -345,10 +349,7 @@ public class ReverseProxy implements HttpProxy { } - private HttpRequest buildCallRequestBuffer(ProxyRequest proxyRequest,String body) { - String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey()); - String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey()); - String key = appCode + ":" + apiCode; + private HttpRequest buildCallRequestBuffer(ProxyRequest proxyRequest,String body,ApiConfig apiConfig) { SocketAddress socketAddress = ProxyTool.resolveOriginAddress(proxyRequest.proxiedRequest()); HttpRequest requestBuffer; String requestURI = proxyRequest.getURI(); @@ -369,7 +370,7 @@ public class ReverseProxy implements HttpProxy { requestBuffer = mainWebClient.post(socketAddress.port(), socketAddress.host(), requestURI); break; } - requestBuffer.timeout(AppConfigHandler.getApicodeConfigTimeOut(key)); + requestBuffer.timeout(apiConfig.getTimeout()); requestBuffer.putHeaders(proxyRequest.headers()); // 处理sac请求方式 RequestMethod requestMethod = RequestMethod.getByCode(proxyRequest.getMethod().name()); @@ -393,14 +394,14 @@ public class ReverseProxy implements HttpProxy { // 判断
// 1、是否配置全局加解密.
// 2、apiCode 配置熔断 - String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey()); - String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey()); - String contentType = proxyRequest.headers().get(HttpHeaders.CONTENT_TYPE); - String keyCircuitBreaker = appCode + ":" + apiCode + ":" + "CIRCUIT_BREAKER"; + AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(ctx); + ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(ctx); + String apiServiceType = ctx.get(API_SERVICE_TYPE); + String keyCircuitBreaker = appConfig.getAppCode() + ":" + apiConfig.getApiCode() + ":" + "CIRCUIT_BREAKER"; CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker); - if (AppConfigHandler.isAnalysisBody(appCode, apiCode, contentType)) { - String body = AppConfigHandler.isDataSecurity(appCode) ? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appCode):ctx.body().asString(); - HttpRequest requestBuffer = buildCallRequestBuffer(proxyRequest,body); + if (AppUtils.isAnalysisBody(appConfig,apiConfig,apiServiceType)) { + String body = AppUtils.isEnableDataSecurity(appConfig) ? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appConfig.getAppCode()):ctx.body().asString(); + HttpRequest requestBuffer = buildCallRequestBuffer(proxyRequest,body,apiConfig); try { if (circuitBreaker != null) { return breakerCall(circuitBreaker, proxyRequest,requestBuffer,body); @@ -441,7 +442,7 @@ public class ReverseProxy implements HttpProxy { request.setTimeout(AppConfigHandler.getApicodeConfigTimeOut(key)); Future fut = proxyRequest.send(request); fut.onFailure(err -> { - JsonObject json = SacErrorCode.returnErrorMsg(502); + JsonObject json = AppUtils.getResponseJsonByGatewayError(GatewayError.BAD_GATEWAY); proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json") .putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(502)) .putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(json.size())).setBody(Body.body(json.toBuffer())) diff --git a/sf-vertx/src/main/resources/application.yml b/sf-vertx/src/main/resources/application.yml index 62896e5..17b3643 100644 --- a/sf-vertx/src/main/resources/application.yml +++ b/sf-vertx/src/main/resources/application.yml @@ -3,7 +3,7 @@ server: vertx: deploymentMode: 1 # 1:单机 2:集群 isSSL: false # vertx https或者http启动, ssl 证书有过期时间 - rpcUri: /rpc + rpcUri: /rpc.sac sacResponseHeaderKey: sacErrorCode environment: dev server: