支持mock、优化代码逻辑

上传文件不走加解密、熔断
This commit is contained in:
ztzh_xieyun 2024-05-10 10:28:52 +08:00
parent b7518b3ffd
commit e139863222
16 changed files with 108 additions and 54 deletions

View File

@ -11,5 +11,6 @@ public class ApiConfig implements Serializable {
private String apiCode;
private String uri;
private String method; // 大写
private String mockResponse;
private List<Strategy> strategy; // 策略
}

View File

@ -34,6 +34,7 @@ public class SacErrorCode {
_ERROR.put(10017, "应用请求url被限流");
_ERROR.put(10018, "apiCode与uri不匹配");
_ERROR.put(10019, "请求不支持conetnt-type类型");
_ERROR.put(10020, "uri返回mock数据");
};
public static JsonObject returnErrorMsg(Integer errorCode) {

View File

@ -18,10 +18,10 @@ public class ApiRateLimitHandlerImpl implements ApiRateLimitHandler {
@Override
public void handle(RoutingContext rc) {
String appCode = rc.request().headers().get(AppConfigHandle.getAppCodeHeaderKey());
String apiCode = rc.request().headers().get(AppConfigHandle.getApiCodeHeaderKey());
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
SacCurrentLimiting currentLimiting = AppConfigHandle.getApiCurrentLimiting(appCode, apiCode);
SacCurrentLimiting currentLimiting = AppConfigHandler.getApiCurrentLimiting(appCode, apiCode);
if(currentLimiting != null) {
String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + ":" + appCode + ":" + apiCode + ":" + rc.request().uri()

View File

@ -32,6 +32,7 @@ import io.vertx.circuitbreaker.CircuitBreakerOptions;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import lombok.extern.slf4j.Slf4j;
/***
@ -41,7 +42,7 @@ import lombok.extern.slf4j.Slf4j;
*
*/
@Slf4j
public class AppConfigHandle {
public class AppConfigHandler {
private static VertxConfig VERTX_CONFIG = new VertxConfig();
public static Vertx VERTX;
public static CircuitBreaker CONNECTION_CIRCUIT_BREAKER;
@ -100,8 +101,8 @@ public class AppConfigHandle {
*/
public static boolean isAnalysisBody(String appCode, String apiCode, String contentType) {
String keyCircuitBreaker = appCode + ":" + apiCode + ":" + "CIRCUIT_BREAKER";
CircuitBreaker circuitBreaker = AppConfigHandle.getApiCodeCircuitBreaker(keyCircuitBreaker);
boolean isDataSecurity = AppConfigHandle.isDataSecurity(appCode);
CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
boolean isDataSecurity = AppConfigHandler.isDataSecurity(appCode);
// 文件上传不走加解密
return (isDataSecurity || circuitBreaker != null) && StringUtils.startsWith(contentType, "multipart") == false;
}
@ -143,8 +144,12 @@ public class AppConfigHandle {
return APICODE_CONFIG_MAP.get(key);
}
public static boolean isApicodeUri(String key, String uri) {
return StringUtils.equals(APICODE_CONFIG_MAP.get(key).getUri(), uri);
public static boolean isApicodeUri(String key, String uri, String httpMethod) {
return StringUtils.equals(APICODE_CONFIG_MAP.get(key).getUri(), uri) && StringUtils.equals(httpMethod, APICODE_CONFIG_MAP.get(key).getMethod());
}
public static String mock(String key) {
return APICODE_CONFIG_MAP.get(key).getMockResponse();
}
private static RateLimiterRegistry createRateLimiter(Strategy strategy) {
@ -172,7 +177,7 @@ public class AppConfigHandle {
public static void initAllAppConfig(RedisTemplate<String, String> redisTemplate) throws Exception {
Set<String> set = redisTemplate.opsForZSet().range(RedisKeyConfig.APP_CONFIG_SET_KEY, 0, -1);
for (String appCode : set) {
AppConfigHandle.initAppConfig(redisTemplate, appCode, false);
AppConfigHandler.initAppConfig(redisTemplate, appCode, false);
}
}

View File

@ -18,8 +18,8 @@ public class AppRateLimitHandlerImpl implements AppRateLimitHandler {
@Override
public void handle(RoutingContext rc) {
String appCode = rc.request().headers().get(AppConfigHandle.getAppCodeHeaderKey());
SacCurrentLimiting currentLimiting = AppConfigHandle.getGlobalAppCurrentLimitingConfig(appCode);
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;

View File

@ -78,13 +78,13 @@ public class BodyHandlerImpl implements BodyHandler {
// TODO 改造了这个地方
final HttpServerRequest request = context.request();
final HttpServerResponse response = context.response();
String appCode = context.request().headers().get(AppConfigHandle.getAppCodeHeaderKey());
String apiCode = context.request().headers().get(AppConfigHandle.getApiCodeHeaderKey());
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 {
// TODO 测试异常
isLoadBody = AppConfigHandle.isAnalysisBody(appCode, apiCode, contentType);
isLoadBody = AppConfigHandler.isAnalysisBody(appCode, apiCode, contentType);
} catch (Exception e) {
e.printStackTrace();
context.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE));

View File

@ -0,0 +1,39 @@
package com.sf.vertx.handle;
import io.netty.handler.codec.http.HttpResponseStatus;
public final class HttpMockException extends RuntimeException {
private static final long serialVersionUID = -6984329893540102440L;
private final int statusCode;
private final String payload;
public HttpMockException() {
this(500, null, null);
}
public HttpMockException(int statusCode) {
this(statusCode, null, null);
}
public HttpMockException(int statusCode, Throwable cause) {
this(statusCode, null, cause);
}
public HttpMockException(int statusCode, String payload) {
this(statusCode, payload, null);
}
public HttpMockException(int statusCode, String payload, Throwable cause) {
super(HttpResponseStatus.valueOf(statusCode).reasonPhrase(), cause, false, false);
this.statusCode = statusCode;
this.payload = payload;
}
public int getStatusCode() {
return statusCode;
}
public String getPayload() {
return payload;
}
}

View File

@ -13,26 +13,34 @@ public class ParameterCheckHandlerImpl implements ParameterCheckHandler {
public void handle(RoutingContext rc) {
try {
// TODO 测试异常
String appCode = rc.request().headers().get(AppConfigHandle.getAppCodeHeaderKey());
String apiCode = rc.request().headers().get(AppConfigHandle.getApiCodeHeaderKey());
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)
|| AppConfigHandle.getAppConfig(appCode) == null
|| AppConfigHandle.getApicodeConfigMap(key) == null) {
|| AppConfigHandler.getAppConfig(appCode) == null
|| AppConfigHandler.getApicodeConfigMap(key) == null) {
rc.fail(new HttpException(10012));
return;
}
if(AppConfigHandle.isDisabledAppcode(apiCode)) {
if(AppConfigHandler.isDisabledAppcode(apiCode)) {
rc.fail(new HttpException(10001));
return;
}
String uri = rc.request().uri();
if(AppConfigHandle.isApicodeUri(key, uri) == false) {
String httpMethod = rc.request().method().name();
if(AppConfigHandler.isApicodeUri(key, uri, httpMethod) == false) {
rc.fail(new HttpException(10018));
return;
}
// mock
String mockResponse = AppConfigHandler.mock(key);
if(StringUtils.isNotBlank(mockResponse)) {
rc.fail(new HttpException(10020, mockResponse));
return;
}
} catch (Exception e) {
e.printStackTrace();
rc.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE));

View File

@ -28,12 +28,12 @@
// @Override
// public void handle(RoutingContext rc) {
// try {
// String appCodeHeaderKey = rc.request().headers().get(AppConfigHandle.getAppCodeHeaderKey());
// String apiCodeHeaderKey = rc.request().headers().get(AppConfigHandle.getApiCodeHeaderKey());
// Strategy apiCodeStrategy = AppConfigHandle.getApiCurrentLimiting(appCodeHeaderKey + ":" + apiCodeHeaderKey);
// String appCodeHeaderKey = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
// String apiCodeHeaderKey = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
// Strategy apiCodeStrategy = AppConfigHandler.getApiCurrentLimiting(appCodeHeaderKey + ":" + apiCodeHeaderKey);
//
// Strategy globalApiStrategy = AppConfigHandle.getGlobalApiCurrentLimitingConfig(appCodeHeaderKey);
// Strategy globalAppStrategy = AppConfigHandle.getGlobalAppCurrentLimitingConfig(appCodeHeaderKey);
// Strategy globalApiStrategy = AppConfigHandler.getGlobalApiCurrentLimitingConfig(appCodeHeaderKey);
// Strategy globalAppStrategy = AppConfigHandler.getGlobalAppCurrentLimitingConfig(appCodeHeaderKey);
//
// Strategy apiStrategy = apiCodeStrategy != null ? apiCodeStrategy
// : globalApiStrategy != null ? globalApiStrategy : null;

View File

@ -17,7 +17,7 @@
//@Slf4j
//public class RedisRateLimiter {
// public Map<Integer, Boolean> acquire(RoutingContext rc, Strategy apiStrategy, Strategy appStrategy) {
// String appCodeHeaderKey = rc.request().headers().get(AppConfigHandle.getAppCodeHeaderKey());
// String appCodeHeaderKey = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
// String key = null;
// Map<Integer, Boolean> retMap = new HashMap<>();
// if (apiStrategy != null) {

View File

@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
import com.sf.vertx.api.pojo.VertxConfig;
import com.sf.vertx.constans.RedisKeyConfig;
import com.sf.vertx.handle.ApiRateLimitHandler;
import com.sf.vertx.handle.AppConfigHandle;
import com.sf.vertx.handle.AppConfigHandler;
import com.sf.vertx.handle.AppRateLimitHandler;
import com.sf.vertx.handle.BodyHandler;
import com.sf.vertx.handle.ParameterCheckHandler;
@ -56,7 +56,7 @@ public class DynamicBuildServer implements ApplicationRunner {
// 初始化redis key
redisKeyConfig.init();
// 从redis同步vertx配置
AppConfigHandle.initVertxConfig(redisTemplate);
AppConfigHandler.initVertxConfig(redisTemplate);
// 加载vertx应用配置
appStartLoadData();
@ -68,11 +68,11 @@ public class DynamicBuildServer implements ApplicationRunner {
* @throws Exception
*/
private void appStartLoadData() throws Exception {
Vertx vertx = AppConfigHandle.createVertx();
Vertx vertx = AppConfigHandler.createVertx();
// 从redis同步app配置
AppConfigHandle.initAllAppConfig(redisTemplate);
AppConfigHandler.initAllAppConfig(redisTemplate);
VertxConfig vertxConfig = AppConfigHandle.getVertxConfig();
VertxConfig vertxConfig = AppConfigHandler.getVertxConfig();
// 创建HTTP监听
// 所有ip都能访问
HttpServerOptions httpServerOptions = new HttpServerOptions().setHost("0.0.0.0");

View File

@ -9,7 +9,7 @@ import com.alibaba.fastjson2.JSONObject;
import com.sf.vertx.api.pojo.AppConfig;
import com.sf.vertx.api.pojo.VertxConfig;
import com.sf.vertx.constans.RedisKeyConfig;
import com.sf.vertx.handle.AppConfigHandle;
import com.sf.vertx.handle.AppConfigHandler;
import com.sf.vertx.service.AppConfigService;
import lombok.extern.slf4j.Slf4j;
@ -33,7 +33,7 @@ public class AppConfigServiceImpl implements AppConfigService {
redisTemplate.opsForValue().set(appCodeKey, JSONObject.toJSONString(appConfig));
// 初始化AppConfig本地缓存
AppConfigHandle.initAppConfig(redisTemplate, appConfig.getAppCode(), true);
AppConfigHandler.initAppConfig(redisTemplate, appConfig.getAppCode(), true);
}
@ -48,7 +48,7 @@ public class AppConfigServiceImpl implements AppConfigService {
redisTemplate.delete(appCodeKey);
// 禁用本地缓存
AppConfigHandle.addDisabledAppcode(appConfig.getAppCode());
AppConfigHandler.addDisabledAppcode(appConfig.getAppCode());
}
/***
@ -59,7 +59,7 @@ public class AppConfigServiceImpl implements AppConfigService {
public void saveVertxConfig(VertxConfig vertxConfig) {
String vertxConfigKey = RedisKeyConfig.VERTX_CONFIG_STRING_KEY;
redisTemplate.opsForValue().set(vertxConfigKey, JSONObject.toJSONString(vertxConfig));
AppConfigHandle.initVertxConfig(redisTemplate);
AppConfigHandler.initVertxConfig(redisTemplate);
}
}

View File

@ -6,7 +6,7 @@ import java.util.regex.Pattern;
import com.sf.vertx.api.pojo.Node;
import com.sf.vertx.arithmetic.roundRobin.SacLoadBalancing;
import com.sf.vertx.arithmetic.roundRobin.WeightedRoundRobin;
import com.sf.vertx.handle.AppConfigHandle;
import com.sf.vertx.handle.AppConfigHandler;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.net.SocketAddress;
@ -22,10 +22,10 @@ import lombok.extern.slf4j.Slf4j;
public class ProxyTool {
public static SocketAddress resolveOriginAddress(HttpServerRequest request) {
String appCode = request.getHeader(AppConfigHandle.getAppCodeHeaderKey());
String apiCode = request.getHeader(AppConfigHandle.getApiCodeHeaderKey());
String appCode = request.getHeader(AppConfigHandler.getAppCodeHeaderKey());
String apiCode = request.getHeader(AppConfigHandler.getApiCodeHeaderKey());
log.info("uri:{}, header appCode:{},apiCode:{}", request.uri(), appCode, apiCode);
SacLoadBalancing sacLoadBalancing = AppConfigHandle.getLoadBalancing(appCode + ":" + apiCode);
SacLoadBalancing sacLoadBalancing = AppConfigHandler.getLoadBalancing(appCode + ":" + apiCode);
// TODO 区分httpshttp
Node node = sacLoadBalancing.selectNode();
SocketAddress socketAddress = SocketAddress.inetSocketAddress(node.getPort(), node.getIp());

View File

@ -14,7 +14,7 @@ import java.net.ConnectException;
import java.util.List;
import java.util.function.BiFunction;
import com.sf.vertx.handle.AppConfigHandle;
import com.sf.vertx.handle.AppConfigHandler;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
@ -83,7 +83,7 @@ class SharedClientHttpStreamEndpoint extends ClientHttpEndpointBase<Lease<HttpCl
@Override
public void connect(ContextInternal context, Listener listener,
Handler<AsyncResult<ConnectResult<HttpClientConnection>>> handler) {
AppConfigHandle.CONNECTION_CIRCUIT_BREAKER.executeWithFallback(promise -> {
AppConfigHandler.CONNECTION_CIRCUIT_BREAKER.executeWithFallback(promise -> {
connector.httpConnect(context, ar -> {
if (ar.succeeded()) {
incRefCount();

View File

@ -21,7 +21,7 @@ import org.apache.commons.lang3.StringUtils;
import com.sf.vertx.api.pojo.DataSecurity;
import com.sf.vertx.constans.SacErrorCode;
import com.sf.vertx.handle.AppConfigHandle;
import com.sf.vertx.handle.AppConfigHandler;
import com.sf.vertx.security.MainSecurity;
import com.sf.vertx.utils.ProxyTool;
@ -241,7 +241,7 @@ public class ReverseProxy implements HttpProxy {
}
private Future<ProxyResponse> breakerAndSecurity(CircuitBreaker circuitBreaker, ProxyRequest proxyRequest) {
String appCode = proxyRequest.headers().get(AppConfigHandle.getAppCodeHeaderKey());
String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
SocketAddress socketAddress = ProxyTool.resolveOriginAddress(proxyRequest.proxiedRequest());
return Future.future(p -> {
circuitBreaker.executeWithFallback(promise -> {
@ -352,7 +352,7 @@ public class ReverseProxy implements HttpProxy {
}
private Future<ProxyResponse> security(CircuitBreaker circuitBreaker, ProxyRequest proxyRequest) {
String appCode = proxyRequest.headers().get(AppConfigHandle.getAppCodeHeaderKey());
String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
SocketAddress socketAddress = ProxyTool.resolveOriginAddress(proxyRequest.proxiedRequest());
return Future.future(p -> {
mainWebClient.post(socketAddress.port(), socketAddress.host(), proxyRequest.getURI())
@ -385,16 +385,16 @@ public class ReverseProxy implements HttpProxy {
// 判断<br/>
// 1是否配置全局加解密.<br/>
// 2apiCode 配置熔断
String appCode = proxyRequest.headers().get(AppConfigHandle.getAppCodeHeaderKey());
String apiCode = proxyRequest.headers().get(AppConfigHandle.getApiCodeHeaderKey());
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";
CircuitBreaker circuitBreaker = AppConfigHandle.getApiCodeCircuitBreaker(keyCircuitBreaker);
if (AppConfigHandle.isAnalysisBody(appCode, apiCode, contentType)) {
CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
if (AppConfigHandler.isAnalysisBody(appCode, apiCode, contentType)) {
try {
if (AppConfigHandle.isDataSecurity(appCode) && circuitBreaker != null) {
if (AppConfigHandler.isDataSecurity(appCode) && circuitBreaker != null) {
return breakerAndSecurity(circuitBreaker, proxyRequest);
} else if (AppConfigHandle.isDataSecurity(appCode)) {
} else if (AppConfigHandler.isDataSecurity(appCode)) {
return security(circuitBreaker, proxyRequest);
} else if (circuitBreaker != null) {
return breaker(circuitBreaker, proxyRequest);
@ -453,7 +453,7 @@ public class ReverseProxy implements HttpProxy {
}
private String bodyEncrypt(String body, String appCode) {
DataSecurity dataSecurity = AppConfigHandle.getAppConfig(appCode).getDataSecurity();
DataSecurity dataSecurity = AppConfigHandler.getAppConfig(appCode).getDataSecurity();
switch (dataSecurity.getAlgorithm()) {
case "AES":
return MainSecurity.aesEncrypt(body, dataSecurity.getPrivateKey());
@ -465,7 +465,7 @@ public class ReverseProxy implements HttpProxy {
}
private String bodyDecrypt(String body, String appCode) {
DataSecurity dataSecurity = AppConfigHandle.getAppConfig(appCode).getDataSecurity();
DataSecurity dataSecurity = AppConfigHandler.getAppConfig(appCode).getDataSecurity();
switch (dataSecurity.getAlgorithm()) {
case "AES":
return MainSecurity.aesDecrypt(body, dataSecurity.getPrivateKey());

View File

@ -3,7 +3,7 @@ package com.sf.vertx;
import org.junit.Test;
import com.sf.vertx.api.pojo.VertxConfig;
import com.sf.vertx.handle.AppConfigHandle;
import com.sf.vertx.handle.AppConfigHandler;
import io.vertx.circuitbreaker.CircuitBreaker;
import io.vertx.circuitbreaker.CircuitBreakerOptions;
@ -73,7 +73,7 @@ public class TestCircuitBreaker {
public static void main(String[] args) {
VertxConfig vertxConfig = AppConfigHandle.getVertxConfig();
VertxConfig vertxConfig = AppConfigHandler.getVertxConfig();
// TODO 编解码线程池,后面优化协程等方式
VertxOptions vertxOptions = new VertxOptions();