保留了ReverseProxy反向代理区分body请求,这块代码可以去掉

ReverseProxy 源码部分仅使用了连接超时
request.setTimeout(AppConfigHandler.getApicodeConfigTimeOut(key));

vertx有一个使用问题,一定要注意, 异常情况可能不会抛出, 导致后台一直不返回.
很可能是业务代码逻辑问题, 比如空异常等等
This commit is contained in:
ztzh_xieyun 2024-06-03 14:02:35 +08:00
parent 17da90448e
commit 6fac2783bf
11 changed files with 654 additions and 362 deletions

View File

@ -31,6 +31,7 @@ import com.sf.vertx.enums.GatewayServiceType;
import com.sf.vertx.httpproxy.HttpProxy; import com.sf.vertx.httpproxy.HttpProxy;
import com.sf.vertx.init.SacVertxConfig; import com.sf.vertx.init.SacVertxConfig;
import com.sf.vertx.pojo.ClusterEventMsg; import com.sf.vertx.pojo.ClusterEventMsg;
import com.sf.vertx.pojo.SacCircuitBreaker;
import com.sf.vertx.pojo.SacCurrentLimiting; import com.sf.vertx.pojo.SacCurrentLimiting;
import com.sf.vertx.security.MainSecurity; import com.sf.vertx.security.MainSecurity;
import com.sf.vertx.utils.ProxyTool; import com.sf.vertx.utils.ProxyTool;
@ -96,7 +97,7 @@ public class AppConfigHandler {
private static ConcurrentHashMap<String, List<RouteContent>> APICODE_CONFIG_HEADER_ROUTERCONENT_MAP = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, List<RouteContent>> APICODE_CONFIG_HEADER_ROUTERCONENT_MAP = new ConcurrentHashMap<>();
// apiCode熔断配置 appCode:apiCode - CircuitBreaker // apiCode熔断配置 appCode:apiCode - CircuitBreaker
private static ConcurrentHashMap<String, CircuitBreaker> APICODE_CONFIG_CIRCUIT_BREAKER_MAP = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, SacCircuitBreaker> APICODE_CONFIG_CIRCUIT_BREAKER_MAP = new ConcurrentHashMap<>();
// apicode uri = * - appConfig // apicode uri = * - appConfig
private static ConcurrentHashMap<String, AppConfig> APICODE_APPCONFIG_MAP = new ConcurrentHashMap<>(); private static ConcurrentHashMap<String, AppConfig> APICODE_APPCONFIG_MAP = new ConcurrentHashMap<>();
@ -118,14 +119,14 @@ public class AppConfigHandler {
public static Boolean isServiceTypeOpen(String key) { public static Boolean isServiceTypeOpen(String key) {
return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null
&& StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), "OPEN"); && StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), GatewayServiceType.OPEN.getCode());
} }
public static Boolean isServiceTypeSac(String key) { public static Boolean isServiceTypeSac(String key) {
return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key) != null
&& StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), "SAC"); && StringUtils.equals(APICODE_CONFIG_SERVICE_TYPE_MAP.get(key), GatewayServiceType.SAC.getCode());
} }
public static String getServiceType(String key) { public static String getServiceType(String key) {
return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key); return APICODE_CONFIG_SERVICE_TYPE_MAP.get(key);
} }
@ -171,7 +172,7 @@ public class AppConfigHandler {
return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key) != null; return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key) != null;
} }
public static CircuitBreaker getApiCodeCircuitBreaker(String key) { public static SacCircuitBreaker getApiCodeCircuitBreaker(String key) {
return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key); return APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key);
} }
@ -273,9 +274,11 @@ public class AppConfigHandler {
APICODE_CONFIG_CURRENT_LIMITING_MAP.remove(key); APICODE_CONFIG_CURRENT_LIMITING_MAP.remove(key);
APICODE_APPCONFIG_MAP.remove(apiConfig.getApiCode()); APICODE_APPCONFIG_MAP.remove(apiConfig.getApiCode());
String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER"; String keyCircuitBreaker = key + ":" + "CIRCUIT_BREAKER";
CircuitBreaker circuitBreaker = APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(keyCircuitBreaker); SacCircuitBreaker sacCircuitBreaker = APICODE_CONFIG_CIRCUIT_BREAKER_MAP.get(key);
if (circuitBreaker != null) { if (sacCircuitBreaker != null) {
circuitBreaker.close(); if(sacCircuitBreaker.getCircuitBreaker() != null) {
sacCircuitBreaker.getCircuitBreaker().close();
}
APICODE_CONFIG_CIRCUIT_BREAKER_MAP.remove(keyCircuitBreaker); APICODE_CONFIG_CIRCUIT_BREAKER_MAP.remove(keyCircuitBreaker);
} }
} }
@ -351,7 +354,7 @@ public class AppConfigHandler {
} }
// OPEN模式, 域名映射 // OPEN模式, 域名映射
if (isServiceTypeOpen(key) && StringUtils.equals(apiConfig.getUri(), "*")) { if (isServiceTypeOpen(key)) {
APICODE_APPCONFIG_MAP.put(apiConfig.getApiCode(), appConfig); APICODE_APPCONFIG_MAP.put(apiConfig.getApiCode(), appConfig);
} }
@ -402,11 +405,14 @@ public class AppConfigHandler {
).openHandler(v -> { ).openHandler(v -> {
log.info(keyCircuitBreaker + " Circuit open"); log.info(keyCircuitBreaker + " Circuit open");
}).halfOpenHandler(v -> { }).halfOpenHandler(v -> {
log.info(keyCircuitBreaker + "Circuit halfOpen"); log.info(keyCircuitBreaker + " Circuit halfOpen");
}).closeHandler(v -> { }).closeHandler(v -> {
log.info(keyCircuitBreaker + "Circuit close"); log.info(keyCircuitBreaker + " Circuit close");
}); });
APICODE_CONFIG_CIRCUIT_BREAKER_MAP.put(keyCircuitBreaker, circuitBreaker); SacCircuitBreaker sacCircuitBreaker = new SacCircuitBreaker();
sacCircuitBreaker.setCircuitBreaker(circuitBreaker);
sacCircuitBreaker.setStrategy(strategy);
APICODE_CONFIG_CIRCUIT_BREAKER_MAP.put(key, sacCircuitBreaker);
} }
} }
} }
@ -565,19 +571,27 @@ public class AppConfigHandler {
Route routeSac = mainHttpRouter.post(rpcUri()); Route routeSac = mainHttpRouter.post(rpcUri());
routeSac.handler(CorsHandler.create().addRelativeOrigin(".*")) routeSac.handler(CorsHandler.create().addRelativeOrigin(".*"))
.handler(ParameterCheckHandler.create(GatewayServiceType.SAC)) .handler(ParameterCheckHandler.create(GatewayServiceType.SAC))
.handler(AppRateLimitHandler.create(rateLimitModel)).handler(ApiRateLimitHandler.create(rateLimitModel)) .handler(AppRateLimitHandler.create(rateLimitModel))
.handler(BodyPreCheckHandler.create()).handler(BodyHandler.create().setHandleFileUploads(false)) .handler(ApiRateLimitHandler.create(rateLimitModel))
.handler(BodyPostAnalysisHandler.create()).handler(BodyPostCheckHandler.create()) .handler(BodyPreCheckHandler.create())
.handler(SacRouteRequestHandler.create(mainWebClient)).handler(ProxyHandler.create(proxy)) .handler(BodyHandler.create().setHandleFileUploads(false))
.handler(BodyPostAnalysisHandler.create())
.handler(BodyPostCheckHandler.create())
.handler(SacRouteRequestHandler.create(mainWebClient))
.handler(ProxyHandler.create(mainWebClient, proxy))
.failureHandler(RestfulFailureHandler.create()); .failureHandler(RestfulFailureHandler.create());
Route routeOpen = mainHttpRouter.route(); Route routeOpen = mainHttpRouter.route();
routeOpen.handler(CorsHandler.create().addRelativeOrigin(".*")) routeOpen.handler(CorsHandler.create().addRelativeOrigin(".*"))
.handler(ParameterCheckHandler.create(GatewayServiceType.OPEN)) .handler(ParameterCheckHandler.create(GatewayServiceType.OPEN))
.handler(AppRateLimitHandler.create(rateLimitModel)).handler(ApiRateLimitHandler.create(rateLimitModel)) .handler(AppRateLimitHandler.create(rateLimitModel))
.handler(BodyPreCheckHandler.create()).handler(BodyHandler.create().setHandleFileUploads(false)) .handler(ApiRateLimitHandler.create(rateLimitModel))
.handler(BodyPostCheckHandler.create()).handler(SacRouteRequestHandler.create(mainWebClient)) .handler(BodyPreCheckHandler.create())
.handler(ProxyHandler.create(proxy)).failureHandler(RestfulFailureHandler.create()); .handler(BodyHandler.create().setHandleFileUploads(false))
.handler(BodyPostCheckHandler.create())
.handler(SacRouteRequestHandler.create(mainWebClient))
.handler(ProxyHandler.create(mainWebClient, proxy))
.failureHandler(RestfulFailureHandler.create());
} }
private static void loadVertxOptions(VertxOptions vertxOptions) { private static void loadVertxOptions(VertxOptions vertxOptions) {
@ -590,7 +604,7 @@ public class AppConfigHandler {
} }
// TODO // TODO
blockedThreadCheckInterval = 1000000L; // blockedThreadCheckInterval = 1000000L;
if (blockedThreadCheckInterval != -1) { if (blockedThreadCheckInterval != -1) {
vertxOptions.setBlockedThreadCheckInterval(blockedThreadCheckInterval); // 不打印Thread blocked 阻塞日志 vertxOptions.setBlockedThreadCheckInterval(blockedThreadCheckInterval); // 不打印Thread blocked 阻塞日志
} }

View File

@ -134,8 +134,9 @@ public class BodyHandlerImpl implements BodyHandler {
// TODO 改造了这个地方 在真正解析body之前验证是否需要继续解析 // TODO 改造了这个地方 在真正解析body之前验证是否需要继续解析
AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(context); AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(context);
ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(context); ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(context);
String contentType = context.request().headers().get(HttpHeaders.CONTENT_TYPE);
String apiServiceType = context.get(API_SERVICE_TYPE); String apiServiceType = context.get(API_SERVICE_TYPE);
if (!AppUtils.isAnalysisBody(appConfig, apiConfig, apiServiceType)){ if (!AppUtils.isAnalysisBody(appConfig, apiConfig, apiServiceType, contentType)){
context.next(); context.next();
return; return;
} }

View File

@ -1,14 +1,3 @@
/*
* Copyright (c) 2011-2021 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package com.sf.vertx.handle; package com.sf.vertx.handle;
import com.sf.vertx.httpproxy.HttpProxy; import com.sf.vertx.httpproxy.HttpProxy;
@ -16,6 +5,7 @@ import com.sf.vertx.httpproxy.HttpProxy;
import io.vertx.codegen.annotations.VertxGen; import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.WebClient;
/** /**
* @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a> * @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
@ -24,11 +14,15 @@ import io.vertx.ext.web.RoutingContext;
@VertxGen @VertxGen
public interface ProxyHandler extends Handler<RoutingContext> { public interface ProxyHandler extends Handler<RoutingContext> {
static ProxyHandler create(HttpProxy httpProxy) { static ProxyHandler create(WebClient mainWebClient, HttpProxy httpProxy) {
return new ProxyHandlerImpl(httpProxy); return new ProxyHandlerImpl(mainWebClient, httpProxy);
} }
static ProxyHandler create(HttpProxy httpProxy, int port, String host) { static ProxyHandler create(HttpProxy httpProxy) {
return new ProxyHandlerImpl(httpProxy, port, host); return new ProxyHandlerImpl(httpProxy);
} }
static ProxyHandler create(HttpProxy httpProxy, int port, String host) {
return new ProxyHandlerImpl(httpProxy, port, host);
}
} }

View File

@ -3,25 +3,34 @@ package com.sf.vertx.handle;
import com.sf.vertx.httpproxy.HttpProxy; import com.sf.vertx.httpproxy.HttpProxy;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.WebClient;
/** /**
* @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a> * @author <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
*/ */
public class ProxyHandlerImpl implements ProxyHandler { public class ProxyHandlerImpl implements ProxyHandler {
private final HttpProxy httpProxy; private final HttpProxy httpProxy;
private WebClient mainWebClient;
public ProxyHandlerImpl(HttpProxy httpProxy) { public ProxyHandlerImpl(WebClient mainWebClient, HttpProxy httpProxy) {
this.httpProxy = httpProxy; this.httpProxy = httpProxy;
} this.mainWebClient = mainWebClient;
}
public ProxyHandlerImpl(HttpProxy httpProxy, int port, String host) { public ProxyHandlerImpl(HttpProxy httpProxy) {
this.httpProxy = httpProxy.origin(port, host); this.httpProxy = httpProxy;
} }
@Override public ProxyHandlerImpl(HttpProxy httpProxy, int port, String host) {
public void handle(RoutingContext ctx) { this.httpProxy = httpProxy.origin(port, host);
httpProxy.handle(ctx.request()); }
}
} @Override
public void handle(RoutingContext ctx) {
// TODO 改造了这个地方
httpProxy.handle(mainWebClient, ctx);
// 原始代码只有如下一句
// httpProxy.handle(ctx.request());
}
}

View File

@ -1,8 +1,9 @@
package com.sf.vertx.handle; package com.sf.vertx.handle;
import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE; import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE;
import static com.sf.vertx.constans.SACConstants.CACHE_KEY_CONNECTOR;
import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.apache.commons.lang3.StringUtils.EMPTY;
import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE_SAC;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -13,13 +14,16 @@ import com.sf.vertx.api.pojo.AppConfig;
import com.sf.vertx.enums.GatewayError; import com.sf.vertx.enums.GatewayError;
import com.sf.vertx.enums.RequestMethod; import com.sf.vertx.enums.RequestMethod;
import com.sf.vertx.exception.ServiceException; import com.sf.vertx.exception.ServiceException;
import com.sf.vertx.pojo.SacCircuitBreaker;
import com.sf.vertx.utils.AppUtils; import com.sf.vertx.utils.AppUtils;
import com.sf.vertx.utils.ProxyTool; import com.sf.vertx.utils.ProxyTool;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import io.vertx.circuitbreaker.CircuitBreaker; import io.vertx.circuitbreaker.CircuitBreaker;
import io.vertx.circuitbreaker.OpenCircuitException;
import io.vertx.core.buffer.Buffer; import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpHeaders;
import io.vertx.core.impl.NoStackTraceThrowable;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.core.net.SocketAddress; import io.vertx.core.net.SocketAddress;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
@ -36,10 +40,10 @@ public class SacRouteRequestHandlerImpl implements SacRouteRequestHandler {
this.mainWebClient = mainWebClient; this.mainWebClient = mainWebClient;
} }
private void breakerCall(RoutingContext ctx, CircuitBreaker circuitBreaker, HttpRequest<Buffer> requestBuffer, private void breakerCall(RoutingContext ctx, SacCircuitBreaker sacCircuitBreaker, HttpRequest<Buffer> requestBuffer,
String body) { String body) {
String appCode = AppUtils.getAppConfigFromRoutingContext(ctx).getAppCode(); String appCode = AppUtils.getAppConfigFromRoutingContext(ctx).getAppCode();
circuitBreaker.executeWithFallback(promise -> { sacCircuitBreaker.getCircuitBreaker().executeWithFallback(promise -> {
requestBuffer.sendJson(body, h -> { requestBuffer.sendJson(body, h -> {
if (h.succeeded()) { if (h.succeeded()) {
log.info("==========uri:{},response http code:{}", ctx.request().uri(), h.result().statusCode()); log.info("==========uri:{},response http code:{}", ctx.request().uri(), h.result().statusCode());
@ -52,18 +56,25 @@ public class SacRouteRequestHandlerImpl implements SacRouteRequestHandler {
promise.fail("2"); promise.fail("2");
} }
JsonObject responseData = h.result().bodyAsJsonObject(); JsonObject responseData = h.result().bodyAsJsonObject();
log.info("responseData:{}", responseData); //log.info("responseData:{}", responseData);
Buffer buffer; Buffer buffer;
// 加密 // 加密
if (AppConfigHandler.isDataSecurity(appCode)) { if (AppConfigHandler.isDataSecurity(appCode)) {
String dataStr = AppConfigHandler.bodyEncrypt(responseData.toString(), appCode); String dataStr = AppConfigHandler.bodyEncrypt(responseData.toString(), appCode);
log.info("encrypt dataStr:{}", dataStr); //log.info("encrypt dataStr:{}", dataStr);
buffer = Buffer.buffer(dataStr); buffer = Buffer.buffer(dataStr);
} else { } else {
buffer = responseData.toBuffer(); buffer = responseData.toBuffer();
} }
ctx.response().setChunked(true).setStatusCode(200).putHeader("Content-Type", "application/json")
.end(buffer); Integer statusCode = h.result().statusCode() > 0 ? h.result().statusCode() : 200;
// TODO 和客户端组件沟通
// String contentType = h.result().headers().get(HttpHeaders.CONTENT_TYPE) != null
// ? h.result().headers().get(HttpHeaders.CONTENT_TYPE)
// : "application/json";
String contentType = "application/json";
ctx.response().setChunked(true).setStatusCode(statusCode)
.putHeader(HttpHeaders.CONTENT_TYPE, contentType).end(buffer);
} else { } else {
// end(proxyRequest, 502); // end(proxyRequest, 502);
// Throwable throwable = new Throwable("error port"); // Throwable throwable = new Throwable("error port");
@ -72,18 +83,27 @@ public class SacRouteRequestHandlerImpl implements SacRouteRequestHandler {
} }
}); });
}, v -> { }, v -> {
// 需要传递当前状态half-open , close, 还是统计失败次数 log.info(sacCircuitBreaker.getCircuitBreaker().name() + " executed when the circuit is opened:{}", v);
log.info(circuitBreaker.name() + " executed when the circuit is opened:{}", v.getMessage()); if (v instanceof OpenCircuitException) {
// v value is null, default return 3
log.info(sacCircuitBreaker.getCircuitBreaker().name() + " open circuit");
} else if (v instanceof NoStackTraceThrowable) {
log.info(sacCircuitBreaker.getCircuitBreaker().name() + " close circuit");
return v.getMessage();
} else {
log.info(sacCircuitBreaker.getCircuitBreaker().name() + " half open circuit");
return v.getMessage();
}
return "3"; return "3";
}, ar -> { }, ar -> {
log.info(circuitBreaker.name() + " interface failed result.{} ", ar); log.info(sacCircuitBreaker.getCircuitBreaker().name() + " interface failed result.{} ", ar);
if (StringUtils.equals(ar.result(), "3")) { // 全开,熔断 if (StringUtils.equals(ar.result(), "3")) { // 全开,熔断
ctx.fail(new ServiceException(GatewayError.BAD_GATEWAY)); ctx.fail(new ServiceException(GatewayError.REQUEST_URL_IS_BROKEN, sacCircuitBreaker.getStrategy().getDefaultResponse()));
} }
}); });
} }
private void jsonCall(RoutingContext ctx, HttpRequest<Buffer> requestBuffer, String body) { private void normalCall(RoutingContext ctx, HttpRequest<Buffer> requestBuffer, String body) {
String appCode = AppUtils.getAppConfigFromRoutingContext(ctx).getAppCode(); String appCode = AppUtils.getAppConfigFromRoutingContext(ctx).getAppCode();
requestBuffer.sendJson(body, h -> { requestBuffer.sendJson(body, h -> {
if (h.succeeded()) { if (h.succeeded()) {
@ -131,7 +151,7 @@ public class SacRouteRequestHandlerImpl implements SacRouteRequestHandler {
} }
requestBuffer.timeout(apiConfig.getTimeout()); // 超时 requestBuffer.timeout(apiConfig.getTimeout()); // 超时
requestBuffer.putHeaders(ctx.request().headers()); requestBuffer.putHeaders(ctx.request().headers());
// 处理sac请求方式 // 处理sac请求方式/{a}/{b}
RequestMethod requestMethod = RequestMethod.getByCode(ctx.request().method().name()); RequestMethod requestMethod = RequestMethod.getByCode(ctx.request().method().name());
if (RequestMethod.GET.equals(requestMethod) || RequestMethod.DELETE.equals(requestMethod) if (RequestMethod.GET.equals(requestMethod) || RequestMethod.DELETE.equals(requestMethod)
|| RequestMethod.HEAD.equals(requestMethod)) { || RequestMethod.HEAD.equals(requestMethod)) {
@ -154,19 +174,20 @@ public class SacRouteRequestHandlerImpl implements SacRouteRequestHandler {
// 判断body是否解析 // 判断body是否解析
AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(ctx); AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(ctx);
ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(ctx); ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(ctx);
String apiServiceType = ctx.get(API_SERVICE_TYPE);
String contentType = ctx.request().headers().get(HttpHeaders.CONTENT_TYPE); String contentType = ctx.request().headers().get(HttpHeaders.CONTENT_TYPE);
if (AppUtils.isAnalysisBody(appConfig, apiConfig, contentType)) { if (AppUtils.isAnalysisBody(appConfig, apiConfig, apiServiceType, contentType)) {
String keyCircuitBreaker = appConfig.getAppCode() + ":" + apiConfig.getApiCode() + ":" + "CIRCUIT_BREAKER"; String keyCircuitBreaker = appConfig.getAppCode() + CACHE_KEY_CONNECTOR + apiConfig.getApiCode();
CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker); SacCircuitBreaker sacCircuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
String body = AppUtils.isEnableDataSecurity(appConfig) String body = AppUtils.isEnableDataSecurity(appConfig)
? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appConfig.getAppCode()) ? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appConfig.getAppCode())
: ctx.body().asString(); : ctx.body().asString();
HttpRequest<Buffer> requestBuffer = buildCallRequestBuffer(ctx, body, apiConfig); HttpRequest<Buffer> requestBuffer = buildCallRequestBuffer(ctx, body, apiConfig);
try { try {
if (circuitBreaker != null) { if (sacCircuitBreaker != null && sacCircuitBreaker.getCircuitBreaker() != null) {
breakerCall(ctx, circuitBreaker, requestBuffer, body); breakerCall(ctx, sacCircuitBreaker, requestBuffer, body);
} else { } else {
jsonCall(ctx, requestBuffer, body); normalCall(ctx, requestBuffer, body);
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -10,6 +10,11 @@
*/ */
package com.sf.vertx.httpproxy; package com.sf.vertx.httpproxy;
import java.util.function.BiFunction;
import java.util.function.Function;
import com.sf.vertx.httpproxy.impl.ReverseProxy;
import io.vertx.codegen.annotations.Fluent; import io.vertx.codegen.annotations.Fluent;
import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.codegen.annotations.VertxGen; import io.vertx.codegen.annotations.VertxGen;
@ -20,13 +25,11 @@ import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.RequestOptions; import io.vertx.core.http.RequestOptions;
import io.vertx.core.net.SocketAddress; import io.vertx.core.net.SocketAddress;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.WebClient;
import io.vertx.httpproxy.ProxyInterceptor; import io.vertx.httpproxy.ProxyInterceptor;
import io.vertx.httpproxy.ProxyOptions; import io.vertx.httpproxy.ProxyOptions;
import com.sf.vertx.httpproxy.impl.ReverseProxy;
import java.util.function.BiFunction;
import java.util.function.Function;
/** /**
* Handles the HTTP reverse proxy logic between the <i><b>user agent</b></i> and the <i><b>origin</b></i>. * Handles the HTTP reverse proxy logic between the <i><b>user agent</b></i> and the <i><b>origin</b></i>.
* <p> * <p>
@ -118,4 +121,5 @@ public interface HttpProxy extends Handler<HttpServerRequest> {
*/ */
void handle(HttpServerRequest request); void handle(HttpServerRequest request);
void handle(WebClient mainWebClient, RoutingContext ctx);
} }

View File

@ -10,6 +10,8 @@
*/ */
package com.sf.vertx.httpproxy.impl; package com.sf.vertx.httpproxy.impl;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -17,11 +19,21 @@ import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import org.apache.commons.lang3.StringUtils;
import com.sf.vertx.enums.GatewayError;
import com.sf.vertx.enums.RequestMethod;
import com.sf.vertx.handle.AppConfigHandler; import com.sf.vertx.handle.AppConfigHandler;
import com.sf.vertx.httpproxy.HttpProxy; import com.sf.vertx.httpproxy.HttpProxy;
import com.sf.vertx.utils.AppUtils;
import com.sf.vertx.utils.ProxyTool;
import cn.hutool.core.util.StrUtil;
import io.vertx.circuitbreaker.CircuitBreaker;
import io.vertx.circuitbreaker.OpenCircuitException;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
@ -29,7 +41,14 @@ import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse; import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.impl.NoStackTraceThrowable;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.NetSocket; import io.vertx.core.net.NetSocket;
import io.vertx.core.net.SocketAddress;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.WebClient;
import io.vertx.httpproxy.Body;
import io.vertx.httpproxy.ProxyContext; import io.vertx.httpproxy.ProxyContext;
import io.vertx.httpproxy.ProxyInterceptor; import io.vertx.httpproxy.ProxyInterceptor;
import io.vertx.httpproxy.ProxyOptions; import io.vertx.httpproxy.ProxyOptions;
@ -37,223 +56,410 @@ import io.vertx.httpproxy.ProxyRequest;
import io.vertx.httpproxy.ProxyResponse; import io.vertx.httpproxy.ProxyResponse;
import io.vertx.httpproxy.cache.CacheOptions; import io.vertx.httpproxy.cache.CacheOptions;
import io.vertx.httpproxy.spi.cache.Cache; import io.vertx.httpproxy.spi.cache.Cache;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ReverseProxy implements HttpProxy { public class ReverseProxy implements HttpProxy {
private final HttpClient client; private final HttpClient client;
private final boolean supportWebSocket; private final boolean supportWebSocket;
private BiFunction<HttpServerRequest, HttpClient, Future<HttpClientRequest>> selector = (req, client) -> Future.failedFuture("No origin available"); private BiFunction<HttpServerRequest, HttpClient, Future<HttpClientRequest>> selector = (req, client) -> Future
private final List<ProxyInterceptor> interceptors = new ArrayList<>(); .failedFuture("No origin available");
private final List<ProxyInterceptor> interceptors = new ArrayList<>();
private RoutingContext ctx;
private WebClient mainWebClient;
public ReverseProxy(ProxyOptions options, HttpClient client) { public ReverseProxy(ProxyOptions options, HttpClient client) {
CacheOptions cacheOptions = options.getCacheOptions(); CacheOptions cacheOptions = options.getCacheOptions();
if (cacheOptions != null) { if (cacheOptions != null) {
Cache<String, Resource> cache = cacheOptions.newCache(); Cache<String, Resource> cache = cacheOptions.newCache();
addInterceptor(new CachingFilter(cache)); addInterceptor(new CachingFilter(cache));
} }
this.client = client; this.client = client;
this.supportWebSocket = options.getSupportWebSocket(); this.supportWebSocket = options.getSupportWebSocket();
} }
@Override @Override
public HttpProxy originRequestProvider(BiFunction<HttpServerRequest, HttpClient, Future<HttpClientRequest>> provider) { public HttpProxy originRequestProvider(
selector = provider; BiFunction<HttpServerRequest, HttpClient, Future<HttpClientRequest>> provider) {
return this; selector = provider;
} return this;
}
@Override @Override
public HttpProxy addInterceptor(ProxyInterceptor interceptor) { public HttpProxy addInterceptor(ProxyInterceptor interceptor) {
interceptors.add(interceptor); interceptors.add(interceptor);
return this; return this;
} }
@Override
public void handle(WebClient mainWebClient, RoutingContext ctx) {
// TODO 改造了这个地方
this.ctx = ctx;
this.mainWebClient = mainWebClient;
handle(ctx.request());
}
@Override @Override
public void handle(HttpServerRequest request) { public void handle(HttpServerRequest request) {
ProxyRequest proxyRequest = ProxyRequest.reverseProxy(request); ProxyRequest proxyRequest = ProxyRequest.reverseProxy(request);
// Encoding sanity check // Encoding sanity check
Boolean chunked = HttpUtils.isChunked(request.headers()); Boolean chunked = HttpUtils.isChunked(request.headers());
if (chunked == null) { if (chunked == null) {
end(proxyRequest, 400); end(proxyRequest, 400);
return; return;
} }
// WebSocket upgrade tunneling // WebSocket upgrade tunneling
if (supportWebSocket && io.vertx.core.http.impl.HttpUtils.canUpgradeToWebSocket(request)) { if (supportWebSocket && io.vertx.core.http.impl.HttpUtils.canUpgradeToWebSocket(request)) {
handleWebSocketUpgrade(proxyRequest); handleWebSocketUpgrade(proxyRequest);
return; return;
} }
Proxy proxy = new Proxy(proxyRequest); Proxy proxy = new Proxy(proxyRequest);
proxy.filters = interceptors.listIterator(); proxy.filters = interceptors.listIterator();
proxy.sendRequest().compose(proxy::sendProxyResponse); proxy.sendRequest().compose(proxy::sendProxyResponse);
} }
private void handleWebSocketUpgrade(ProxyRequest proxyRequest) { private void handleWebSocketUpgrade(ProxyRequest proxyRequest) {
HttpServerRequest proxiedRequest = proxyRequest.proxiedRequest(); HttpServerRequest proxiedRequest = proxyRequest.proxiedRequest();
resolveOrigin(proxiedRequest).onComplete(ar -> { resolveOrigin(proxiedRequest).onComplete(ar -> {
if (ar.succeeded()) { if (ar.succeeded()) {
HttpClientRequest request = ar.result(); HttpClientRequest request = ar.result();
request.setMethod(HttpMethod.GET); request.setMethod(HttpMethod.GET);
request.setURI(proxiedRequest.uri()); request.setURI(proxiedRequest.uri());
request.headers().addAll(proxiedRequest.headers()); request.headers().addAll(proxiedRequest.headers());
Future<HttpClientResponse> fut2 = request.connect(); Future<HttpClientResponse> fut2 = request.connect();
proxiedRequest.handler(request::write); proxiedRequest.handler(request::write);
proxiedRequest.endHandler(v -> request.end()); proxiedRequest.endHandler(v -> request.end());
proxiedRequest.resume(); proxiedRequest.resume();
fut2.onComplete(ar2 -> { fut2.onComplete(ar2 -> {
if (ar2.succeeded()) { if (ar2.succeeded()) {
HttpClientResponse proxiedResponse = ar2.result(); HttpClientResponse proxiedResponse = ar2.result();
if (proxiedResponse.statusCode() == 101) { if (proxiedResponse.statusCode() == 101) {
HttpServerResponse response = proxiedRequest.response(); HttpServerResponse response = proxiedRequest.response();
response.setStatusCode(101); response.setStatusCode(101);
response.headers().addAll(proxiedResponse.headers()); response.headers().addAll(proxiedResponse.headers());
Future<NetSocket> otherso = proxiedRequest.toNetSocket(); Future<NetSocket> otherso = proxiedRequest.toNetSocket();
otherso.onComplete(ar3 -> { otherso.onComplete(ar3 -> {
if (ar3.succeeded()) { if (ar3.succeeded()) {
NetSocket responseSocket = ar3.result(); NetSocket responseSocket = ar3.result();
NetSocket proxyResponseSocket = proxiedResponse.netSocket(); NetSocket proxyResponseSocket = proxiedResponse.netSocket();
responseSocket.handler(proxyResponseSocket::write); responseSocket.handler(proxyResponseSocket::write);
proxyResponseSocket.handler(responseSocket::write); proxyResponseSocket.handler(responseSocket::write);
responseSocket.closeHandler(v -> proxyResponseSocket.close()); responseSocket.closeHandler(v -> proxyResponseSocket.close());
proxyResponseSocket.closeHandler(v -> responseSocket.close()); proxyResponseSocket.closeHandler(v -> responseSocket.close());
} else { } else {
// Find reproducer // Find reproducer
System.err.println("Handle this case"); System.err.println("Handle this case");
ar3.cause().printStackTrace(); ar3.cause().printStackTrace();
} }
}); });
} else { } else {
// Rejection // Rejection
proxiedRequest.resume(); proxiedRequest.resume();
end(proxyRequest, proxiedResponse.statusCode()); end(proxyRequest, proxiedResponse.statusCode());
} }
} else { } else {
proxiedRequest.resume(); proxiedRequest.resume();
end(proxyRequest, 502); end(proxyRequest, 502);
} }
}); });
} else { } else {
proxiedRequest.resume(); proxiedRequest.resume();
end(proxyRequest, 502); end(proxyRequest, 502);
} }
}); });
} }
private void end(ProxyRequest proxyRequest, int sc) { /***
proxyRequest * 返回错误
.response() *
.release() * @param proxyRequest
.setStatusCode(sc) * @param sc
.putHeader(HttpHeaders.CONTENT_LENGTH, "0") */
.setBody(null) private void end(ProxyRequest proxyRequest, int sc) {
.send(); 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()))
.send();
}
private Future<HttpClientRequest> resolveOrigin(HttpServerRequest proxiedRequest) { private Future<HttpClientRequest> resolveOrigin(HttpServerRequest proxiedRequest) {
return selector.apply(proxiedRequest, client); return selector.apply(proxiedRequest, client);
} }
private class Proxy implements ProxyContext { private class Proxy implements ProxyContext {
private final ProxyRequest request; private final ProxyRequest request;
private ProxyResponse response; private ProxyResponse response;
private final Map<String, Object> attachments = new HashMap<>(); private final Map<String, Object> attachments = new HashMap<>();
private ListIterator<ProxyInterceptor> filters; private ListIterator<ProxyInterceptor> filters;
private Proxy(ProxyRequest request) { private Proxy(ProxyRequest request) {
this.request = request; this.request = request;
} }
@Override @Override
public void set(String name, Object value) { public void set(String name, Object value) {
attachments.put(name, value); attachments.put(name, value);
} }
@Override @Override
public <T> T get(String name, Class<T> type) { public <T> T get(String name, Class<T> type) {
Object o = attachments.get(name); Object o = attachments.get(name);
return type.isInstance(o) ? type.cast(o) : null; return type.isInstance(o) ? type.cast(o) : null;
} }
@Override @Override
public ProxyRequest request() { public ProxyRequest request() {
return request; return request;
} }
@Override @Override
public Future<ProxyResponse> sendRequest() { public Future<ProxyResponse> sendRequest() {
if (filters.hasNext()) { if (filters.hasNext()) {
ProxyInterceptor next = filters.next(); ProxyInterceptor next = filters.next();
return next.handleProxyRequest(this); return next.handleProxyRequest(this);
} else { } else {
return sendProxyRequest(request); return sendProxyRequest(request);
} }
} }
@Override @Override
public ProxyResponse response() { public ProxyResponse response() {
return response; return response;
} }
@Override @Override
public Future<Void> sendResponse() { public Future<Void> sendResponse() {
if (filters.hasPrevious()) { if (filters.hasPrevious()) {
ProxyInterceptor filter = filters.previous(); ProxyInterceptor filter = filters.previous();
return filter.handleProxyResponse(this); return filter.handleProxyResponse(this);
} else { } else {
return response.send(); return response.send();
} }
} }
private Future<ProxyResponse> sendProxyRequest(ProxyRequest proxyRequest) { private Future<ProxyResponse> breakerCall(CircuitBreaker circuitBreaker, ProxyRequest proxyRequest,
Future<HttpClientRequest> f = resolveOrigin(proxyRequest.proxiedRequest()); HttpRequest<Buffer> requestBuffer, String body) {
f.onFailure(err -> { String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
// Should this be done here ? I don't think so return Future.future(p -> {
HttpServerRequest proxiedRequest = proxyRequest.proxiedRequest(); circuitBreaker.executeWithFallback(promise -> {
proxiedRequest.resume(); requestBuffer.sendJson(body, h -> {
Promise<Void> promise = Promise.promise(); if (h.succeeded()) {
proxiedRequest.exceptionHandler(promise::tryFail); log.info("==========uri:{},response http code:{}", proxyRequest.getURI(),
proxiedRequest.endHandler(promise::tryComplete); h.result().statusCode());
promise.future().onComplete(ar2 -> { if (h.result().statusCode() == 200) {
end(proxyRequest, 502); // promise.complete();
}); promise.complete("1");
}); } else {
return f.compose(a -> sendProxyRequest(proxyRequest, a)); // Throwable throwable = new Throwable("error port");
} // promise.fail(throwable);
promise.fail("2");
}
// 释放资源
proxyRequest.release();
JsonObject responseData = h.result().bodyAsJsonObject();
log.info("responseData:{}", responseData);
Buffer buffer;
// 加密
if (AppConfigHandler.isDataSecurity(appCode)) {
String dataStr = AppConfigHandler.bodyEncrypt(responseData.toString(), appCode);
log.info("encrypt dataStr:{}", dataStr);
buffer = Buffer.buffer(dataStr);
} else {
buffer = responseData.toBuffer();
}
ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
.putHeader("content-type", "application/json").setBody(Body.body(buffer));
p.complete(proxyResponse);
} else {
// end(proxyRequest, 502);
// Throwable throwable = new Throwable("error port");
// promise.fail(throwable);
promise.fail("3");
}
});
}, v -> {
log.info(circuitBreaker.name() + " executed when the circuit is opened:{}", v);
if (v instanceof OpenCircuitException) {
log.info(circuitBreaker.name() + " open circuit");
} else if (v instanceof NoStackTraceThrowable) {
log.info(circuitBreaker.name() + " close circuit");
return v.getMessage();
} else {
log.info(circuitBreaker.name() + " half open circuit");
return v.getMessage();
}
return "3";
}, ar -> {
log.info(circuitBreaker.name() + " interface failed result.{} ", ar);
if (StringUtils.equals(ar.result(), "3")) { // 全开,熔断
end(proxyRequest, 10016);
}
});
});
}
private void setConnectionTimeout(ProxyRequest proxyRequest, HttpClientRequest request) { private Future<ProxyResponse> normalCall(ProxyRequest proxyRequest, HttpRequest<Buffer> requestBuffer,
String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey()); String body) {
String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey()); String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
String key = appCode + ":" + apiCode; return Future.future(p -> {
request.idleTimeout(AppConfigHandler.getApicodeConfigTimeOut(key)); requestBuffer.sendJson(body, h -> {
} if (h.succeeded()) {
log.info("==========uri:{},response http code:{}", proxyRequest.getURI(),
private Future<ProxyResponse> sendProxyRequest(ProxyRequest proxyRequest, HttpClientRequest request) { h.result().statusCode());
Future<ProxyResponse> fut = proxyRequest.send(request); if (h.result().statusCode() == 200) {
// 超时 // 释放资源
setConnectionTimeout(proxyRequest, request); proxyRequest.release();
fut.onFailure(err -> { JsonObject responseData = h.result().bodyAsJsonObject();
proxyRequest.proxiedRequest().response().setStatusCode(502).end(); log.info("responseData:{}", responseData);
}); Buffer bodyBuffer = responseData.toBuffer();
return fut; // 加密
} if (AppConfigHandler.isDataSecurity(appCode)) {
String dataStr = AppConfigHandler.bodyEncrypt(responseData.toString(), appCode);
log.info("encrypt dataStr:{}", dataStr);
bodyBuffer = Buffer.buffer(dataStr);
}
ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
.putHeader("content-type", "application/json").setBody(Body.body(bodyBuffer));
p.complete(proxyResponse);
}
} else {
log.info("interface retrun error.{}", proxyRequest.getURI());
end(proxyRequest, 502);
}
});
});
}
private Future<Void> sendProxyResponse(ProxyResponse response) { private HttpRequest<Buffer> buildCallRequestBuffer(ProxyRequest proxyRequest, String body) {
String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey());
String key = appCode + ":" + apiCode;
SocketAddress socketAddress = ProxyTool.resolveOriginAddress(proxyRequest.proxiedRequest());
HttpRequest<Buffer> requestBuffer;
String requestURI = proxyRequest.getURI();
switch (proxyRequest.getMethod().name()) {
case "PUT":
requestBuffer = mainWebClient.put(socketAddress.port(), socketAddress.host(), requestURI);
break;
case "DELETE":
requestBuffer = mainWebClient.delete(socketAddress.port(), socketAddress.host(), requestURI);
break;
case "HEAD":
requestBuffer = mainWebClient.head(socketAddress.port(), socketAddress.host(), requestURI);
break;
case "GET":
requestBuffer = mainWebClient.get(socketAddress.port(), socketAddress.host(), requestURI);
break;
default:
requestBuffer = mainWebClient.post(socketAddress.port(), socketAddress.host(), requestURI);
break;
}
requestBuffer.timeout(AppConfigHandler.getApicodeConfigTimeOut(key));
requestBuffer.putHeaders(proxyRequest.headers());
// 处理sac请求方式
RequestMethod requestMethod = RequestMethod.getByCode(proxyRequest.getMethod().name());
if (RequestMethod.GET.equals(requestMethod) || RequestMethod.DELETE.equals(requestMethod)
|| RequestMethod.HEAD.equals(requestMethod)) {
JsonObject jsonBody = new JsonObject(body);
Map<String, String> queryParams = new HashMap<>();
for (Map.Entry<String, Object> entry : jsonBody) {
String val = entry.getValue() != null ? entry.getValue().toString() : EMPTY;
queryParams.put(entry.getKey(), val);
requestURI = StrUtil.replace(requestURI, "{" + entry.getKey() + "}", val);
}
requestBuffer.uri(requestURI);
requestBuffer.queryParams().addAll(queryParams);
}
return requestBuffer;
}
this.response = response; private Future<ProxyResponse> sendProxyRequest(ProxyRequest proxyRequest) {
// 判断<br/>
// 1是否配置全局加解密.<br/>
// 2apiCode 配置熔断
// AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(ctx);
// ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(ctx);
// String apiServiceType = ctx.get(API_SERVICE_TYPE);
// String contentType = ctx.request().headers().get(HttpHeaders.CONTENT_TYPE);
// String keyCircuitBreaker = appConfig.getAppCode() + ":" + apiConfig.getApiCode() + ":" + "CIRCUIT_BREAKER";
// CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
// if (AppUtils.isAnalysisBody(appConfig, apiConfig, apiServiceType, contentType)) {
// String body = AppConfigHandler.isDataSecurity(appConfig.getAppCode())
// ? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appConfig.getAppCode())
// : ctx.body().asString();
// HttpRequest<Buffer> requestBuffer = buildCallRequestBuffer(proxyRequest, body);
// try {
// if (circuitBreaker != null) {
// return breakerCall(circuitBreaker, proxyRequest, requestBuffer, body);
// } else {
// return normalCall(proxyRequest, requestBuffer, body);
// }
// } catch (Exception e) {
// e.printStackTrace();
// int errorCode = 10014;
// if (e instanceof HttpException) {
// errorCode = ((HttpException) e).getStatusCode();
// }
// throw new HttpException(errorCode);
// }
// } else {
Future<HttpClientRequest> f = resolveOrigin(proxyRequest.proxiedRequest());
f.onFailure(err -> {
log.info("error:", err);
// Should this be done here ? I don't think so
HttpServerRequest proxiedRequest = proxyRequest.proxiedRequest();
proxiedRequest.resume();
Promise<Void> promise = Promise.promise();
proxiedRequest.exceptionHandler(promise::tryFail);
proxiedRequest.endHandler(promise::tryComplete);
promise.future().onComplete(ar2 -> {
end(proxyRequest, 502);
});
});
return f.compose(a -> sendProxyRequest(proxyRequest, a));
// }
// Check validity }
Boolean chunked = HttpUtils.isChunked(response.headers());
if (chunked == null) {
// response.request().release(); // Is it needed ???
end(response.request(), 501);
return Future.succeededFuture(); // should use END future here ???
}
return sendResponse(); private Future<ProxyResponse> sendProxyRequest(ProxyRequest proxyRequest, HttpClientRequest request) {
} String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
} String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey());
String key = appCode + ":" + apiCode;
request.setTimeout(AppConfigHandler.getApicodeConfigTimeOut(key));
Future<ProxyResponse> fut = proxyRequest.send(request);
fut.onFailure(err -> {
JsonObject errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.BAD_GATEWAY);
proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json")
.putHeader(AppConfigHandler.sacResponseHeaderKey(),
String.valueOf(GatewayError.BAD_GATEWAY.getCode()))
.putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(errorJson.size()))
.setBody(Body.body(errorJson.toBuffer())).send();
// proxyRequest.proxiedRequest().response().setStatusCode(502).end();
});
return fut;
}
private Future<Void> sendProxyResponse(ProxyResponse response) {
this.response = response;
// Check validity
Boolean chunked = HttpUtils.isChunked(response.headers());
if (chunked == null) {
// response.request().release(); // Is it needed ???
end(response.request(), 501);
return Future.succeededFuture(); // should use END future here ???
}
return sendResponse();
}
}
} }

View File

@ -0,0 +1,13 @@
package com.sf.vertx.pojo;
import com.sf.vertx.api.pojo.Strategy;
import io.vertx.circuitbreaker.CircuitBreaker;
import lombok.Data;
@Data
public class SacCircuitBreaker {
private CircuitBreaker circuitBreaker;
private Strategy strategy;
}

View File

@ -74,5 +74,5 @@ public class MainSecurity {
// + " }\n" // + " }\n"
// + "}", "dadddsdfadfadsfa33323223")); // + "}", "dadddsdfadfadsfa33323223"));
// System.out.println(aesDecrypt("59A69B6BBCF046C3CF9953C5CC078CC638602D454BBCE8CF8F0DA6AF1F3A4707686263C834A612C5C6F22D9F897B13B434A53E32AAD4036E12A5098565AB1AD352B400FC23354ECE977DDC670F793992D7F884264A9689B000E37157B4D41351", "dadddsdfadfadsfa33323223")); // System.out.println(aesDecrypt("59A69B6BBCF046C3CF9953C5CC078CC638602D454BBCE8CF8F0DA6AF1F3A4707686263C834A612C5C6F22D9F897B13B434A53E32AAD4036E12A5098565AB1AD352B400FC23354ECE977DDC670F793992D7F884264A9689B000E37157B4D41351", "dadddsdfadfadsfa33323223"));
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,6 @@
package com.sf.vertx.utils; package com.sf.vertx.utils;
import static com.sf.vertx.constans.SACConstants.CACHE_KEY_CONNECTOR;
import static com.sf.vertx.constans.SACConstants.API_CONFIG; import static com.sf.vertx.constans.SACConstants.API_CONFIG;
import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE; import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE;
import static com.sf.vertx.constans.SACConstants.APP_CONFIG; import static com.sf.vertx.constans.SACConstants.APP_CONFIG;
@ -18,10 +19,14 @@ import com.sf.vertx.api.pojo.MockResponse;
import com.sf.vertx.enums.GatewayError; import com.sf.vertx.enums.GatewayError;
import com.sf.vertx.enums.GatewayServiceType; import com.sf.vertx.enums.GatewayServiceType;
import com.sf.vertx.enums.MatchType; import com.sf.vertx.enums.MatchType;
import com.sf.vertx.enums.RequestMethod;
import com.sf.vertx.exception.ServiceException; import com.sf.vertx.exception.ServiceException;
import com.sf.vertx.handle.AppConfigHandler;
import com.sf.vertx.pojo.SacCircuitBreaker;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import io.vertx.circuitbreaker.CircuitBreaker;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.RoutingContext;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
@ -250,7 +255,12 @@ public class AppUtils {
return getResponseJsonByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR); return getResponseJsonByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR);
} }
public static boolean isAnalysisBody(AppConfig appConfig, ApiConfig apiConfig, String contentType) { public static boolean isAnalysisBody(AppConfig appConfig, ApiConfig apiConfig,String apiServiceType, String contentType) {
// 不是Mock(是mock模式的话存在body就解析)
if (AppUtils.isEnableMockApi(apiConfig)) {
return true;
}
// 文件上传不走加解密
if (StringUtils.startsWith(contentType, "multipart")) { if (StringUtils.startsWith(contentType, "multipart")) {
return false; return false;
} }
@ -260,6 +270,20 @@ public class AppUtils {
return false; return false;
} }
return isEnableDataSecurity(appConfig); // 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() + CACHE_KEY_CONNECTOR + apiConfig.getApiCode();
SacCircuitBreaker sacCircuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
boolean isDataSecurity = AppUtils.isEnableDataSecurity(appConfig);
return (isDataSecurity || sacCircuitBreaker != null);
} }
} }