diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AdvancedConfig.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AdvancedConfig.java new file mode 100644 index 0000000..b5d75a8 --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AdvancedConfig.java @@ -0,0 +1,16 @@ +package com.sf.vertx.api.pojo; + +import java.io.Serializable; + +import lombok.Data; + +@Data +public class AdvancedConfig implements Serializable { + private static final long serialVersionUID = -6935223493505821401L; + private Integer retryStrategy; // 请求失败重试次数 + private Integer timeout; // 请求超时时间 + private String cacheConfig; // 响应数据的缓存策略 + private String zipConfig;// 响应压缩 + private String monitorCconfig;// 监控指标 + +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AppConfig.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AppConfig.java index 9ce8261..9eb08f5 100644 --- a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AppConfig.java +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/AppConfig.java @@ -8,8 +8,11 @@ import lombok.Data; @Data public class AppConfig implements Serializable { private static final long serialVersionUID = 1518165296680157119L; - private String appCode; + private String appCode; // 应用唯一码, app访问uri添加前缀,用于网关区分多应用 private boolean exclusiveService; // 预留字段, 独立端口 - private List nodeList; - private List strategyList; + private Integer exclusiveGatewayConfigId; // 独享网关配置编号 + private EnvironmentConfig environmentConfig; // 环境配置 + private List service; // 服务 + private AdvancedConfig advancedConfig; // 高级配置 + private DataSecurity dataSecurity; // 数据加解密 } diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/DataSecurity.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/DataSecurity.java index c52af2e..ec515a1 100644 --- a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/DataSecurity.java +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/DataSecurity.java @@ -7,6 +7,7 @@ import lombok.Data; @Data public class DataSecurity implements Serializable { private static final long serialVersionUID = 5034274428665340830L; + private String key; //加密串 private String algorithm; // 国密加解密 private String publicKey; // 公钥 private String privateKey; // 私钥 diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/EnvironmentConfig.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/EnvironmentConfig.java new file mode 100644 index 0000000..0c6431f --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/EnvironmentConfig.java @@ -0,0 +1,17 @@ +package com.sf.vertx.api.pojo; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import lombok.Data; + +@Data +public class EnvironmentConfig implements Serializable { + private static final long serialVersionUID = -3952046909425019869L; + private Integer defaultId; // 默认环境配置编号 + private Map> environmentGroup; // 环境节点 + + + +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/GatewayInterface.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/GatewayInterface.java index 6c47fc9..dcb921f 100644 --- a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/GatewayInterface.java +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/GatewayInterface.java @@ -8,5 +8,6 @@ import lombok.Data; public class GatewayInterface implements Serializable { private static final long serialVersionUID = -313734935498432381L; private String uri; + private boolean uriRegular; // uri 正则 private String method; // 大写 } diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Router.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Router.java new file mode 100644 index 0000000..2464ce1 --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Router.java @@ -0,0 +1,16 @@ +package com.sf.vertx.api.pojo; + +import java.io.Serializable; +import java.util.Map; + +import lombok.Data; + +@Data +public class Router implements Serializable { + private static final long serialVersionUID = -4471811880134025210L; + private String domain; // 域名 + private Map headers; // 头字段 + private String headerVal; // 头字段 + private Integer environmentId; // 环境配置编号 + +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/SacService.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/SacService.java new file mode 100644 index 0000000..a30617b --- /dev/null +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/SacService.java @@ -0,0 +1,15 @@ +package com.sf.vertx.api.pojo; + +import java.io.Serializable; +import java.util.List; + +import lombok.Data; + +@Data +public class SacService implements Serializable { + private static final long serialVersionUID = -5171112142954536813L; + private Strategy strategy; // 策略 + private List uriList; // uri列表 + private Router router; // 路由 + +} diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Strategy.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Strategy.java index 3897aa5..d11ed38 100644 --- a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Strategy.java +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Strategy.java @@ -1,7 +1,6 @@ package com.sf.vertx.api.pojo; import java.io.Serializable; -import java.util.List; import lombok.Data; @@ -13,9 +12,5 @@ import lombok.Data; @Data public class Strategy implements Serializable { private static final long serialVersionUID = -8831406773224882471L; - private DataSecurity dataSecurity; - private List gatewayInterfaceList; - private HttpClientOptionsConfig httpClientOptionsConfig; // 高并发情况,配置接口连接池 - - + // 限流熔断 } diff --git a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/VertxConfig.java b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/VertxConfig.java index 9a50994..b71e6a7 100644 --- a/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/VertxConfig.java +++ b/sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/VertxConfig.java @@ -9,5 +9,6 @@ public class VertxConfig implements Serializable { private static final long serialVersionUID = -1706421732809219829L; private Integer port; // 启动端口 private VertxOptionsConfig vertxOptionsConfig; + private HttpClientOptionsConfig httpClientOptionsConfig; // 配置Vert端口连接池 } diff --git a/sf-vertx/src/main/java/com/sf/AdminApplication.java b/sf-vertx/src/main/java/com/sf/AdminApplication.java index 7e91c8e..d0a5333 100644 --- a/sf-vertx/src/main/java/com/sf/AdminApplication.java +++ b/sf-vertx/src/main/java/com/sf/AdminApplication.java @@ -15,7 +15,7 @@ import lombok.extern.slf4j.Slf4j; */ @Slf4j @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) -public class AdminApplication { +public class AdminApplication { // 全局 ApplicationContext 实例,方便 getBean 拿到 Spring/SpringBoot 注入的类实例 private static ApplicationContext APPLICATION_CONTEXT; diff --git a/sf-vertx/src/main/java/com/sf/vertx/controller/AppConfigController.java b/sf-vertx/src/main/java/com/sf/vertx/controller/AppConfigController.java index d9309bd..f45106b 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/controller/AppConfigController.java +++ b/sf-vertx/src/main/java/com/sf/vertx/controller/AppConfigController.java @@ -25,7 +25,7 @@ public class AppConfigController { private AppConfigService appConfigService; @PostMapping("/addAppConfig") - public String addAppConfig(@RequestBody AppConfig appConfig) { + public String addAppConfig(@RequestBody String appConfig) { appConfigService.addAppConfig(appConfig); return null; } diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandler.java b/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandler.java new file mode 100644 index 0000000..f4596c5 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandler.java @@ -0,0 +1,144 @@ +package com.sf.vertx.handle; + +/* + * Copyright 2014 Red Hat, Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * The Apache License v2.0 is available at + * http://www.opensource.org/licenses/apache2.0.php + * + * You may elect to redistribute this code under either of these licenses. + */ + +import io.vertx.codegen.annotations.Fluent; +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; + +/** + * A handler which gathers the entire request body and sets it on the {@link RoutingContext}. + *

+ * It also handles HTTP file uploads and can be used to limit body sizes. + * + * @author Tim Fox + */ +@VertxGen +public interface BodyHandler extends Handler { + + /** + * Default max size for a request body in bytes = {@code 10485760}, i.e. 10 megabytes + */ + long DEFAULT_BODY_LIMIT = 10 * 1024 * 1024; + + /** + * Default uploads directory on server for file uploads + */ + String DEFAULT_UPLOADS_DIRECTORY = "file-uploads"; + + /** + * Default value of whether form attributes should be merged into request params + */ + boolean DEFAULT_MERGE_FORM_ATTRIBUTES = true; + + /** + * Default value of whether uploaded files should be removed after handling the request + */ + boolean DEFAULT_DELETE_UPLOADED_FILES_ON_END = false; + + /** + * Default value of whether to pre-allocate the body buffer size according to the content-length HTTP request header + */ + boolean DEFAULT_PREALLOCATE_BODY_BUFFER = false; + + /** + * Create a body handler with defaults. + * + * @return the body handler + */ + static BodyHandler create() { + return new BodyHandlerImpl(); + } + + /** + * Create a body handler setting if it should handle file uploads. + * + * @param handleFileUploads true if files upload should be handled + * @return the body handler + */ + static BodyHandler create(boolean handleFileUploads) { + return new BodyHandlerImpl(handleFileUploads); + } + + /** + * Create a body handler and use the given upload directory. + * + * @param uploadDirectory the uploads directory + * @return the body handler + */ + static BodyHandler create(String uploadDirectory) { + return new BodyHandlerImpl(uploadDirectory); + } + + /** + * Set whether file uploads will be handled. + * + * @param handleFileUploads true if they should be handled + * @return reference to this for fluency + */ + @Fluent + BodyHandler setHandleFileUploads(boolean handleFileUploads); + + /** + * Set the maximum body size in bytes, {@code -1} means no limit. + * + * @param bodyLimit the max size in bytes + * @return reference to this for fluency + */ + @Fluent + BodyHandler setBodyLimit(long bodyLimit); + + /** + * Set the uploads directory to use. + * + * @param uploadsDirectory the uploads directory + * @return reference to this for fluency + */ + @Fluent + BodyHandler setUploadsDirectory(String uploadsDirectory); + + /** + * Set whether form attributes will be added to the request parameters. + * + * @param mergeFormAttributes true if they should be merged + * @return reference to this for fluency + */ + @Fluent + BodyHandler setMergeFormAttributes(boolean mergeFormAttributes); + + /** + * Set whether uploaded files should be removed after handling the request. + * + * @param deleteUploadedFilesOnEnd true if uploaded files should be removed after handling the request + * @return reference to this for fluency + */ + @Fluent + BodyHandler setDeleteUploadedFilesOnEnd(boolean deleteUploadedFilesOnEnd); + + /** + * Pre-allocate the body buffer according to the value parsed from content-length header. + * The buffer is capped at 64KB + * @param isPreallocateBodyBuffer {@code true} if body buffer is pre-allocated according to the size + * read from content-length Header. + * {code false} if body buffer is pre-allocated to 1KB, and is resized dynamically + * @return reference to this for fluency + */ + @Fluent + BodyHandler setPreallocateBodyBuffer(boolean isPreallocateBodyBuffer); + +} 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 new file mode 100644 index 0000000..6c15a7f --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java @@ -0,0 +1,382 @@ +package com.sf.vertx.handle; + +/* + * Copyright 2014 Red Hat, Inc. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Apache License v2.0 which accompanies this distribution. + * + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * The Apache License v2.0 is available at + * http://www.opensource.org/licenses/apache2.0.php + * + * You may elect to redistribute this code under either of these licenses. + */ + +import io.netty.handler.codec.DecoderException; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.file.FileSystem; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.core.http.HttpVersion; +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.impl.FileUploadImpl; +import io.vertx.ext.web.impl.RoutingContextInternal; + +import java.io.File; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.lang3.StringUtils; + +import com.sf.vertx.init.DynamicBuildServer; +import com.sf.vertx.service.impl.AppConfigServiceImpl; + +/** + * @author Tim Fox + */ +public class BodyHandlerImpl implements BodyHandler { + + private static final Logger LOG = LoggerFactory.getLogger(BodyHandlerImpl.class); + + private long bodyLimit = DEFAULT_BODY_LIMIT; + private boolean handleFileUploads; + private String uploadsDir; + private boolean mergeFormAttributes = DEFAULT_MERGE_FORM_ATTRIBUTES; + private boolean deleteUploadedFilesOnEnd = DEFAULT_DELETE_UPLOADED_FILES_ON_END; + private boolean isPreallocateBodyBuffer = DEFAULT_PREALLOCATE_BODY_BUFFER; + private static final int DEFAULT_INITIAL_BODY_BUFFER_SIZE = 1024; // bytes + + public BodyHandlerImpl() { + this(true, DEFAULT_UPLOADS_DIRECTORY); + } + + public BodyHandlerImpl(boolean handleFileUploads) { + this(handleFileUploads, DEFAULT_UPLOADS_DIRECTORY); + } + + public BodyHandlerImpl(String uploadDirectory) { + this(true, uploadDirectory); + } + + private BodyHandlerImpl(boolean handleFileUploads, String uploadDirectory) { + this.handleFileUploads = handleFileUploads; + setUploadsDirectory(uploadDirectory); + } + + @Override + public void handle(RoutingContext context) { + final HttpServerRequest request = context.request(); + final HttpServerResponse response = context.response(); + String sacAppHeaderKey = request.getHeader(DynamicBuildServer.SAC_APP_HEADER_KEY); + if (StringUtils.isNotBlank(sacAppHeaderKey) && AppConfigServiceImpl.appDataSecurity(sacAppHeaderKey)) { + // 加解密在proxy拦截器解析跳转 + // =======源码流程 +// 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); + + 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; + } + } + + // 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()); + } + + context.next(); + } + } else { + // 非加解密不处理 + context.next(); + return; + } + } + + @Override + public BodyHandler setHandleFileUploads(boolean handleFileUploads) { + this.handleFileUploads = handleFileUploads; + return this; + } + + @Override + public BodyHandler setBodyLimit(long bodyLimit) { + this.bodyLimit = bodyLimit; + return this; + } + + @Override + public BodyHandler setUploadsDirectory(String uploadsDirectory) { + this.uploadsDir = uploadsDirectory; + return this; + } + + @Override + public BodyHandler setMergeFormAttributes(boolean mergeFormAttributes) { + this.mergeFormAttributes = mergeFormAttributes; + return this; + } + + @Override + public BodyHandler setDeleteUploadedFilesOnEnd(boolean deleteUploadedFilesOnEnd) { + this.deleteUploadedFilesOnEnd = deleteUploadedFilesOnEnd; + return this; + } + + @Override + public BodyHandler setPreallocateBodyBuffer(boolean isPreallocateBodyBuffer) { + this.isPreallocateBodyBuffer = isPreallocateBodyBuffer; + return this; + } + + private long parseContentLengthHeader(HttpServerRequest request) { + String contentLength = request.getHeader(HttpHeaders.CONTENT_LENGTH); + if (contentLength == null || contentLength.isEmpty()) { + return -1; + } + try { + long parsedContentLength = Long.parseLong(contentLength); + return parsedContentLength < 0 ? -1 : parsedContentLength; + } catch (NumberFormatException ex) { + return -1; + } + } + + private class BHandler implements Handler { + private static final int MAX_PREALLOCATED_BODY_BUFFER_BYTES = 65535; + + final RoutingContext context; + final long contentLength; + Buffer body; + boolean failed; + final AtomicInteger uploadCount = new AtomicInteger(); + boolean ended; + long uploadSize = 0L; + final boolean isMultipart; + final boolean isUrlEncoded; + + public BHandler(RoutingContext context, long contentLength) { + this.context = context; + this.contentLength = contentLength; + // the request clearly states that there should + // be a body, so we respect the client and ensure + // that the body will not be null + if (contentLength != -1) { + initBodyBuffer(); + } + + List fileUploads = context.fileUploads(); + + final String contentType = context.request().getHeader(HttpHeaders.CONTENT_TYPE); + if (contentType == null) { + isMultipart = false; + isUrlEncoded = false; + } else { + final String lowerCaseContentType = contentType.toLowerCase(); + isMultipart = lowerCaseContentType.startsWith(HttpHeaderValues.MULTIPART_FORM_DATA.toString()); + isUrlEncoded = lowerCaseContentType + .startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString()); + } + + if (isMultipart || isUrlEncoded) { + context.request().setExpectMultipart(true); + if (handleFileUploads) { + makeUploadDir(context.vertx().fileSystem()); + } + context.request().uploadHandler(upload -> { + if (bodyLimit != -1 && upload.isSizeAvailable()) { + // we can try to abort even before the upload starts + long size = uploadSize + upload.size(); + if (size > bodyLimit) { + failed = true; + context.cancelAndCleanupFileUploads(); + context.fail(413); + return; + } + } + if (handleFileUploads) { + // we actually upload to a file with a generated filename + uploadCount.incrementAndGet(); + String uploadedFileName = new File(uploadsDir, UUID.randomUUID().toString()).getPath(); + FileUploadImpl fileUpload = new FileUploadImpl(context.vertx().fileSystem(), uploadedFileName, + upload); + fileUploads.add(fileUpload); + Future fut = upload.streamToFileSystem(uploadedFileName); + fut.onComplete(ar -> { + if (fut.succeeded()) { + uploadEnded(); + } else { + context.cancelAndCleanupFileUploads(); + context.fail(ar.cause()); + } + }); + } + }); + } + + context.request().exceptionHandler(t -> { + context.cancelAndCleanupFileUploads(); + int sc = 200; + if (t instanceof DecoderException) { + // bad request + sc = 400; + if (t.getCause() != null) { + t = t.getCause(); + } + } + context.fail(sc, t); + }); + } + + private void initBodyBuffer() { + int initialBodyBufferSize; + if (contentLength < 0) { + initialBodyBufferSize = DEFAULT_INITIAL_BODY_BUFFER_SIZE; + } else if (contentLength > MAX_PREALLOCATED_BODY_BUFFER_BYTES) { + initialBodyBufferSize = MAX_PREALLOCATED_BODY_BUFFER_BYTES; + } else { + initialBodyBufferSize = (int) contentLength; + } + + if (bodyLimit != -1) { + initialBodyBufferSize = (int) Math.min(initialBodyBufferSize, bodyLimit); + } + + this.body = Buffer.buffer(initialBodyBufferSize); + } + + private void makeUploadDir(FileSystem fileSystem) { + if (!fileSystem.existsBlocking(uploadsDir)) { + fileSystem.mkdirsBlocking(uploadsDir); + } + } + + @Override + public void handle(Buffer buff) { + if (failed) { + return; + } + uploadSize += buff.length(); + if (bodyLimit != -1 && uploadSize > bodyLimit) { + failed = true; + context.cancelAndCleanupFileUploads(); + context.fail(413); + } else { + // multipart requests will not end up in the request body + // url encoded should also not, however jQuery by default + // post in urlencoded even if the payload is something else + if (!isMultipart /* && !isUrlEncoded */) { + if (body == null) { + initBodyBuffer(); + } + body.appendBuffer(buff); + } + } + } + + void uploadEnded() { + int count = uploadCount.decrementAndGet(); + // only if parsing is done and count is 0 then all files have been processed + if (ended && count == 0) { + doEnd(); + } + } + + void end(Void v) { + // this marks the end of body parsing, calling doEnd should + // only be possible from this moment onwards + ended = true; + + // only if parsing is done and count is 0 then all files have been processed + if (uploadCount.get() == 0) { + doEnd(); + } + } + + void doEnd() { + + if (failed || context.failed()) { + context.cancelAndCleanupFileUploads(); + return; + } + + if (deleteUploadedFilesOnEnd) { + context.addBodyEndHandler(x -> context.cancelAndCleanupFileUploads()); + } + + HttpServerRequest req = context.request(); + if (mergeFormAttributes && req.isExpectMultipart()) { + req.params().addAll(req.formAttributes()); + } + ((RoutingContextInternal) context).setBody(body); + // release body as it may take lots of memory + body = null; + + context.next(); + } + } +} diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandler.java b/sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandler.java new file mode 100644 index 0000000..29d3ba5 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandler.java @@ -0,0 +1,28 @@ +package com.sf.vertx.handle; + +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.Handler; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.client.WebClient; +import io.vertx.httpproxy.HttpProxy; + +/** + * @author Emad Alblueshi + */ + +@VertxGen +public interface ProxyHandler extends Handler { + + static ProxyHandler create(WebClient mainWebClient, HttpProxy httpProxy) { + return new ProxyHandlerImpl(mainWebClient, httpProxy); + } + + static ProxyHandler create(HttpProxy httpProxy) { + return new ProxyHandlerImpl(httpProxy); + } + + static ProxyHandler create(HttpProxy httpProxy, int port, String host) { + return new ProxyHandlerImpl(httpProxy, port, host); + } +} diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandlerImpl.java new file mode 100644 index 0000000..5802c12 --- /dev/null +++ b/sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandlerImpl.java @@ -0,0 +1,62 @@ +package com.sf.vertx.handle; + +import com.sf.vertx.security.MainSecurity; + +import io.vertx.core.Future; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.PoolOptions; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.client.WebClient; +import io.vertx.httpproxy.Body; +import io.vertx.httpproxy.HttpProxy; +import io.vertx.httpproxy.ProxyRequest; +import io.vertx.httpproxy.ProxyResponse; +import lombok.extern.slf4j.Slf4j; + +/** + * @author Emad Alblueshi + */ +@Slf4j +public class ProxyHandlerImpl implements ProxyHandler { + + private final HttpProxy httpProxy; + private WebClient mainWebClient; + + public ProxyHandlerImpl(WebClient mainWebClient, HttpProxy httpProxy) { + this.httpProxy = httpProxy; + this.mainWebClient = mainWebClient; + } + + public ProxyHandlerImpl(HttpProxy httpProxy) { + this.httpProxy = httpProxy; + } + + public ProxyHandlerImpl(HttpProxy httpProxy, int port, String host) { + this.httpProxy = httpProxy.origin(port, host); + } + + @Override + public void handle(RoutingContext ctx) { + // 创建一个响应并设置参数 +// ctx.request().response().setStatusCode(200) +// .putHeader("content-type", "text/plain").end(body); + // 发起一个请求 + +// this.mainWebClient.post(9198, "127.0.0.1", "/vertx/body").sendJson(ctx.getBodyAsString(), h -> { +// if (h.succeeded()) { +// JsonObject responseData = h.result().bodyAsJsonObject(); +// log.info("responseData:{}", responseData); +// // 加密 +// String dataStr = MainSecurity.aesEncrypt(responseData.toString(), "dadddsdfadfadsfa33323223"); +// log.info("dataStr:{}", dataStr); +// ctx.request().response().setStatusCode(200).putHeader("content-type", "application/json").end(dataStr); +// } +// }); + + // 原始代码只有如下一句 + httpProxy.handle(ctx.request()); + } +} \ No newline at end of file diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/SFProxyHandler.java b/sf-vertx/src/main/java/com/sf/vertx/handle/SFProxyHandler.java deleted file mode 100644 index cd9eee5..0000000 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/SFProxyHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.sf.vertx.handle; - - -import io.vertx.codegen.annotations.VertxGen; -import io.vertx.core.Handler; -import io.vertx.ext.web.RoutingContext; -import io.vertx.httpproxy.HttpProxy; - -/** - * @author Emad Alblueshi - */ - -@VertxGen -public interface SFProxyHandler extends Handler { - - static SFProxyHandler create(HttpProxy httpProxy) { - return new SFProxyHandlerImpl(httpProxy); - } - - static SFProxyHandler create(HttpProxy httpProxy, int port, String host) { - return new SFProxyHandlerImpl(httpProxy, port, host); - } -} diff --git a/sf-vertx/src/main/java/com/sf/vertx/handle/SFProxyHandlerImpl.java b/sf-vertx/src/main/java/com/sf/vertx/handle/SFProxyHandlerImpl.java deleted file mode 100644 index c38df83..0000000 --- a/sf-vertx/src/main/java/com/sf/vertx/handle/SFProxyHandlerImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.sf.vertx.handle; - -import io.vertx.ext.web.RoutingContext; -import io.vertx.httpproxy.HttpProxy; -import lombok.extern.slf4j.Slf4j; - -/** - * @author Emad Alblueshi - */ -@Slf4j -public class SFProxyHandlerImpl implements SFProxyHandler { - - private final HttpProxy httpProxy; - private RoutingContext ctx; - - public SFProxyHandlerImpl(HttpProxy httpProxy) { - this.httpProxy = httpProxy; - } - - public SFProxyHandlerImpl(HttpProxy httpProxy, int port, String host) { - this.httpProxy = httpProxy.origin(port, host); - } - - @Override - public void handle(RoutingContext ctx) { - // String body = ctx.getBodyAsString(); - // log.info("ctx.getBodyAsJson():{}", body); - this.ctx = ctx; - httpProxy.handle(ctx.request()); - } - - public RoutingContext getCtx() { - return ctx; - } - - public void setCtx(RoutingContext ctx) { - this.ctx = ctx; - } - -} \ No newline at end of file diff --git a/sf-vertx/src/main/java/com/sf/vertx/init/DynamicBuildServer.java b/sf-vertx/src/main/java/com/sf/vertx/init/DynamicBuildServer.java index df8118c..6604dbd 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/init/DynamicBuildServer.java +++ b/sf-vertx/src/main/java/com/sf/vertx/init/DynamicBuildServer.java @@ -2,7 +2,9 @@ package com.sf.vertx.init; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.ApplicationArguments; @@ -11,23 +13,33 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import com.sf.vertx.api.pojo.AppConfig; +import com.sf.vertx.api.pojo.GatewayInterface; import com.sf.vertx.api.pojo.Node; +import com.sf.vertx.api.pojo.SacService; import com.sf.vertx.api.pojo.VertxConfig; import com.sf.vertx.arithmetic.roundRobin.SacLoadBalancing; import com.sf.vertx.arithmetic.roundRobin.WeightedRoundRobin; import com.sf.vertx.constans.RedisConfig; +import com.sf.vertx.handle.BodyHandler; +import com.sf.vertx.handle.ProxyHandler; +import com.sf.vertx.security.MainSecurity; import com.sf.vertx.service.AppConfigService; +import com.sf.vertx.service.impl.AppConfigServiceImpl; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.net.SocketAddress; import io.vertx.ext.web.Router; -import io.vertx.ext.web.proxy.handler.ProxyHandler; +import io.vertx.ext.web.client.WebClient; import io.vertx.httpproxy.HttpProxy; +import io.vertx.httpproxy.ProxyContext; +import io.vertx.httpproxy.ProxyInterceptor; +import io.vertx.httpproxy.ProxyResponse; import lombok.extern.slf4j.Slf4j; /*** @@ -40,12 +52,14 @@ import lombok.extern.slf4j.Slf4j; @Order(value = 10) @Component public class DynamicBuildServer implements ApplicationRunner { + public static final String SAC_APP_HEADER_KEY = "sacAppCode"; + private static ConcurrentHashMap SAC_LOADBALANCING_MAP = new ConcurrentHashMap(); @Value("${server.vertx.server.default.port}") - private Integer serverDefaultPort; - + private Integer serverDefaultPort; + @Autowired private AppConfigService appConfigService; - + @Autowired private RedisConfig redisConfig; @@ -53,7 +67,6 @@ public class DynamicBuildServer implements ApplicationRunner { public void run(ApplicationArguments args) throws Exception { // 初始化redis key redisConfig.init(); - // 加载vertx、应用配置 appStartLoadData(); } @@ -62,13 +75,17 @@ public class DynamicBuildServer implements ApplicationRunner { * 应用启动, 从redis读取配置,初始化vertx服务 */ private void appStartLoadData() { - // 编解码线程池 + // TODO 编解码线程池,后面优化协程等方式 Vertx VERTX = Vertx.vertx(new VertxOptions().setWorkerPoolSize(20)); // 创建HTTP监听 - HttpServer server = VERTX.createHttpServer(); + // 所有ip都能访问 + HttpServerOptions httpServerOptions = new HttpServerOptions().setHost("0.0.0.0"); + HttpServer server = VERTX.createHttpServer(httpServerOptions); Router mainHttpRouter = Router.router(VERTX); VertxConfig vertxConfig = appConfigService.loadVertxConfig(); - Integer serverPort = (vertxConfig == null || vertxConfig.getPort() == null) ? serverDefaultPort : vertxConfig.getPort(); + Integer serverPort = (vertxConfig == null || vertxConfig.getPort() == null) ? serverDefaultPort + : vertxConfig.getPort(); + log.info("serverPort:{}", serverPort); server.requestHandler(mainHttpRouter).listen(serverPort, h -> { if (h.succeeded()) { log.info("HTTP端口监听成功:{}", serverPort); @@ -76,52 +93,170 @@ public class DynamicBuildServer implements ApplicationRunner { log.error("HTTP端口监听失败:{}", serverPort); } }); - + ConcurrentHashMap cacheAppConfig = appConfigService.loadAllConfig(); - for (String appCode : cacheAppConfig.keySet()) { - AppConfig appConfig = cacheAppConfig.get(appCode); - // 负载均衡算法 - // 轮训 - SacLoadBalancing sacLoadBalancing = roundRobin(appConfig.getNodeList()); - - - // 有策略 - if (appConfig.getStrategyList() != null && appConfig.getStrategyList().size() > 0) { - - } else { - // 无策略,直接走反向代理 -// HttpClientOptions clientOptions = new HttpClientOptions(); -// clientOptions.setMaxPoolSize(20); // 最大连接池大小 -// clientOptions.setConnectTimeout(5000); // 连接超时 毫秒 -// 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(resolveOriginAddress(sacLoadBalancing, request))); - mainHttpRouter.route().handler(ProxyHandler.create(proxy)); +// HttpClientOptions clientOptions = new HttpClientOptions(); +// clientOptions.setMaxPoolSize(20); // 最大连接池大小 +// clientOptions.setConnectTimeout(5000); // 连接超时 毫秒 +// 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(resolveOriginAddress(cacheAppConfig, request))); + proxy.addInterceptor(new ProxyInterceptor() { + @Override + public Future handleProxyRequest(ProxyContext context) { + // 修改uri context.request().setURI(); + String sacAppHeaderKey = context.request().headers().get(DynamicBuildServer.SAC_APP_HEADER_KEY); + log.info("addInterceptor uri appCode:{}", sacAppHeaderKey); + // 判断是否需要加解析 + if (AppConfigServiceImpl.appDataSecurity(sacAppHeaderKey)) { + + //String data = decode(null, sacAppHeaderKey); + + } + return context.sendRequest(); } - } - } - - public SocketAddress resolveOriginAddress(SacLoadBalancing sacLoadBalancing, HttpServerRequest request) { - // TODO 区分https、http - Node node = sacLoadBalancing.selectNode(); - SocketAddress socketAddress = SocketAddress.inetSocketAddress(node.getPort(), node.getIp()); - log.info("负载均衡跳转地址:{}", socketAddress.host() +";"+socketAddress.port()); - return socketAddress; + }); + // mainHttpRouter.route().handler(ProxyHandler.create(proxy)); + WebClient mainWebClient = WebClient.create(VERTX); + mainHttpRouter.route().handler(BodyHandler.create()).handler(ProxyHandler.create(mainWebClient,proxy)); } - - private SacLoadBalancing roundRobin(List nodeList) { + public SocketAddress resolveOriginAddress(ConcurrentHashMap cacheAppConfig, + HttpServerRequest request) { + String appCode = request.getHeader(SAC_APP_HEADER_KEY); + log.info("uri appCode:{}", appCode); + // TODO 不存在, 抛异常给前端 + + AppConfig appConfig = cacheAppConfig.get(appCode); + if (appConfig != null) { + Integer environmentId = null; + SacLoadBalancing sacLoadBalancing = null; + // 2、是否存在server服务配置 + if (appConfig.getService() != null && appConfig.getService().size() > 0) { + for (SacService service : appConfig.getService()) { + // uri是否匹配 + boolean match = false; + for (GatewayInterface gatewayInterface : service.getUriList()) { + String domain = request.authority().port() == -1 ? request.authority().host() + : request.authority().host() + ":" + request.authority().port(); + // uri匹配(正则或全量匹配) + match = gatewayInterface.isUriRegular() ? regexMatch(gatewayInterface.getUri(), request.uri()) + : StringUtils.equals(gatewayInterface.getUri(), request.uri()); + match = match ? StringUtils.equals(gatewayInterface.getMethod(), request.method().name()) + : false; + // domain匹配 + if (match) { + boolean domainVertify = service.getRouter() != null + && StringUtils.isNotBlank(service.getRouter().getDomain()) + && StringUtils.equals(service.getRouter().getDomain(), domain) ? true : false; + if (domainVertify) { + environmentId = service.getRouter().getEnvironmentId(); + } else { + environmentId = appConfig.getEnvironmentConfig().getDefaultId(); + } + break; + } + } + } + } else { + environmentId = appConfig.getEnvironmentConfig().getDefaultId(); + } + // 初始化负载均衡 + if (SAC_LOADBALANCING_MAP.get(environmentId) != null) { + sacLoadBalancing = SAC_LOADBALANCING_MAP.get(environmentId); + } else { + // 并发影响不大, 只要初始化成功一次即可 + List nodeList = appConfig.getEnvironmentConfig().getEnvironmentGroup().get(environmentId); + if (nodeList != null && nodeList.size() > 0) { + // 初始化负载均衡算法 + sacLoadBalancing = roundRobin(nodeList); + SAC_LOADBALANCING_MAP.put(environmentId, sacLoadBalancing); + } else { + // TODO 抛出异常 + } + } + + // TODO 区分https、http + Node node = sacLoadBalancing.selectNode(); + SocketAddress socketAddress = SocketAddress.inetSocketAddress(node.getPort(), node.getIp()); + log.info("负载均衡跳转地址:{}", socketAddress.host() + ";" + socketAddress.port()); + return socketAddress; + } + // TODO 如果没找到, 如何处理 + return null; + } + +// private String getUriAppCode(String uri) { +// // 1、判断appCode +// int count = 0; +// int appCodeLen = 16; +// StringBuffer appCode = new StringBuffer(); +// for (int i = 0; i < uri.length(); i++) { +// // 限制长度 +// if (appCode.length() == appCodeLen) { +// break; +// } +// char ch = uri.charAt(i); +// if (ch == '/') { +// if (++count == 2) { +// break; +// } +// } else { +// appCode.append(ch); +// } +// } +// return appCode.toString(); +// } + + private static boolean regexMatch(String pattern, String target) { + return Pattern.matches(pattern, target); + } + + /*** + * 解密 + */ + private static String decode(AppConfig appConfig, String bodyJson) { + String algorithm = appConfig.getDataSecurity().getAlgorithm(); + String data = null; + switch (algorithm) { + case "aes": + // 解密 + String key = appConfig.getDataSecurity().getKey(); + data = MainSecurity.aesDecrypt(bodyJson, key); + break; + default: + break; + } + return data; + } + + /*** + * 加密 + */ + private static String encryption(AppConfig appConfig, String responseData) { + String algorithm = appConfig.getDataSecurity().getAlgorithm(); + String data = null; + switch (algorithm) { + case "aes": + String key = appConfig.getDataSecurity().getKey(); + data = MainSecurity.aesEncrypt(responseData.toString(), key); + break; + default: + break; + } + return data; + } + + private static SacLoadBalancing roundRobin(List nodeList) { WeightedRoundRobin weightedRoundRobin = new WeightedRoundRobin(); - int weight = 1; - for(Node node : nodeList) { + for (Node node : nodeList) { + int weight = node.getWeight() != null ? node.getWeight() : 1; node.setWeight(weight); node.setCurrentWeight(weight); node.setEffectiveWeight(weight); - weight++; WeightedRoundRobin.totalWeight += node.getEffectiveWeight(); } weightedRoundRobin.init(nodeList); diff --git a/sf-vertx/src/main/java/com/sf/vertx/service/AppConfigService.java b/sf-vertx/src/main/java/com/sf/vertx/service/AppConfigService.java index 8664531..9b30758 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/service/AppConfigService.java +++ b/sf-vertx/src/main/java/com/sf/vertx/service/AppConfigService.java @@ -8,7 +8,7 @@ import com.sf.vertx.api.pojo.VertxConfig; public interface AppConfigService { ConcurrentHashMap loadAllConfig(); - void addAppConfig(AppConfig appConfig); + void addAppConfig(String appConfig); void deleteAppConfig(AppConfig appConfig); diff --git a/sf-vertx/src/main/java/com/sf/vertx/service/impl/AppConfigServiceImpl.java b/sf-vertx/src/main/java/com/sf/vertx/service/impl/AppConfigServiceImpl.java index 943ede9..6c79ea3 100644 --- a/sf-vertx/src/main/java/com/sf/vertx/service/impl/AppConfigServiceImpl.java +++ b/sf-vertx/src/main/java/com/sf/vertx/service/impl/AppConfigServiceImpl.java @@ -1,6 +1,5 @@ package com.sf.vertx.service.impl; -import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -12,8 +11,8 @@ import org.springframework.stereotype.Service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.TypeReference; import com.sf.vertx.api.pojo.AppConfig; -import com.sf.vertx.api.pojo.Node; import com.sf.vertx.api.pojo.VertxConfig; import com.sf.vertx.constans.RedisConfig; import com.sf.vertx.service.AppConfigService; @@ -27,26 +26,24 @@ public class AppConfigServiceImpl implements AppConfigService { private String vertxEnvironment; @Autowired private RedisTemplate redisTemplate; + private static final ConcurrentHashMap cacheAppConfig = new ConcurrentHashMap<>(); + + + public static boolean appDataSecurity(String appCode) { + return cacheAppConfig.get(appCode) != null && cacheAppConfig.get(appCode).getDataSecurity() != null ? true : false; + } /*** * 从redis加载数据 */ public ConcurrentHashMap loadAllConfig() { - ConcurrentHashMap cacheAppConfig = new ConcurrentHashMap<>(); - // 获取所有app列表 Set set = redisTemplate.opsForZSet().range(RedisConfig.APP_CONFIG_SET_KEY, 0, -1); for(String appCode : set) { String appCodeKey = RedisConfig.APP_CONFIG_PREFIX_KEY + ":" + appCode; String appCodeValue = redisTemplate.opsForValue().get(appCodeKey); if(StringUtils.isNotBlank(appCodeValue)) { - AppConfig appConfig = JSON.parseObject(appCodeValue, AppConfig.class); + AppConfig appConfig = JSON.parseObject(appCodeValue, new TypeReference() {}); cacheAppConfig.put(appCode, appConfig); - - //JSONObject jsonObject = JSONObject.parseObject(appCodeValue);//从请求体里获得jsonObject - //String oldGoodsStorageModes = jsonObject.getString("nodeList");//解析成字符串 - //字符串转list - //List oldGoodsStoragemodes = JSON.parseArray(oldGoodsStorageModes,Node.class); - //log.info("oldGoodsStoragemodes:{}", JSON.toJSONString(oldGoodsStoragemodes)); } } log.info("cacheAppConfig:{}", JSON.toJSONString(cacheAppConfig)); @@ -67,10 +64,11 @@ public class AppConfigServiceImpl implements AppConfigService { * 新增、修改 * @param appConfig */ - public void addAppConfig(AppConfig appConfig) { + public void addAppConfig(String appConfigStr) { + AppConfig appConfig = JSON.parseObject(appConfigStr, AppConfig.class); redisTemplate.opsForZSet().add(RedisConfig.APP_CONFIG_SET_KEY, appConfig.getAppCode(), 0); String appCodeKey = RedisConfig.APP_CONFIG_PREFIX_KEY + ":" + appConfig.getAppCode(); - redisTemplate.opsForValue().set(appCodeKey, JSONObject.toJSONString(appConfig)); + redisTemplate.opsForValue().set(appCodeKey, appConfigStr); // 发送redis队列,vertx处理 //String queue = RedisConfig.VETX_ENVIRONMENT_KEY+vertxEnvironment+":list"; diff --git a/sf-vertx/src/main/resources/application.yml b/sf-vertx/src/main/resources/application.yml index b03def3..1ef3b47 100644 --- a/sf-vertx/src/main/resources/application.yml +++ b/sf-vertx/src/main/resources/application.yml @@ -4,7 +4,7 @@ server: environment: dev server: default: - port: 9099 + port: 80 # 服务器的HTTP端口,默认为8080 port: 5566 servlet: @@ -38,9 +38,9 @@ spring: # redis 配置 redis: # 地址 - host: 192.168.1.23 + host: 127.0.0.1 #192.168.1.23 # 端口,默认为6379 - port: 22002 + port: 6379 #22002 # 数据库索引 database: 0 # 密码 diff --git a/sf-vertx/src/test/java/com/sf/vertx/PatternTest.java b/sf-vertx/src/test/java/com/sf/vertx/PatternTest.java new file mode 100644 index 0000000..da35707 --- /dev/null +++ b/sf-vertx/src/test/java/com/sf/vertx/PatternTest.java @@ -0,0 +1,24 @@ +package com.sf.vertx; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Test; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public class PatternTest { + + @Test + public void match() { + String target = "/test/a.html"; + String pattern = "^/test/.*"; +// String target = "hello, world"; +// String pattern = "^hello.* "; + boolean isMatch = Pattern.matches(pattern, target); + log.info("result:{}", isMatch); + } +} diff --git a/sf-vertx/src/test/java/com/sf/vertx/TestProxy.java b/sf-vertx/src/test/java/com/sf/vertx/TestProxy.java index 410c6c8..a484fba 100644 --- a/sf-vertx/src/test/java/com/sf/vertx/TestProxy.java +++ b/sf-vertx/src/test/java/com/sf/vertx/TestProxy.java @@ -5,8 +5,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import com.alibaba.fastjson2.JSONObject; -import com.sf.vertx.handle.SFProxyHandler; -import com.sf.vertx.handle.SFProxyHandlerImpl; +import com.sf.vertx.handle.ProxyHandlerImpl; import com.sf.vertx.security.MainSecurity; import io.vertx.core.AsyncResult; @@ -80,45 +79,45 @@ public class TestProxy { HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request))); - SFProxyHandler sfProxyHandler = SFProxyHandler.create(proxy); + ProxyHandler sfProxyHandler = ProxyHandler.create(proxy); WebClient mainWebClient = WebClient.create(VERTX); proxy.addInterceptor(new ProxyInterceptor() { - @Override - public Future handleProxyRequest(ProxyContext context) { - SFProxyHandlerImpl sfProxyHandlerImpl = (SFProxyHandlerImpl) sfProxyHandler; +// @Override +// public Future handleProxyRequest(ProxyContext context) { +// ProxyHandlerImpl sfProxyHandlerImpl = (ProxyHandlerImpl) sfProxyHandler; // String body = sfProxyHandlerImpl.getCtx().getBodyAsString(); // log.info("ctx.getBodyAsJson():{}", body); - JsonObject bodyJson = sfProxyHandlerImpl.getCtx().getBodyAsJson(); - HttpServerRequest HttpServerRequest = context.request().proxiedRequest(); + //JsonObject bodyJson = sfProxyHandlerImpl.getCtx().getBodyAsJson(); + //HttpServerRequest HttpServerRequest = context.request().proxiedRequest(); // 解密 - String data = MainSecurity.aesDecrypt(bodyJson.getString("data"), "dadddsdfadfadsfa33323223"); - bodyJson.put("data", data); + //String data = MainSecurity.aesDecrypt(bodyJson.getString("data"), "dadddsdfadfadsfa33323223"); + //bodyJson.put("data", data); // end解密 // uri重写 // context.request().setURI("/vertx/body"); - return Future.future(p -> { - mainWebClient.postAbs("http://localhost:9198/vertx/body").sendJson(bodyJson.toString(), h -> { - if (h.succeeded()) { - ProxyRequest proxyRequest = context.request(); - // 释放资源 - proxyRequest.release(); - JsonObject responseData = h.result().bodyAsJsonObject(); - // responseData.toBuffer() - // 加密 - String dataStr = MainSecurity.aesEncrypt(responseData.toString(), - "dadddsdfadfadsfa33323223"); - log.info("dataStr:{}", dataStr); - Buffer buffer = Buffer.buffer(dataStr); - // end 加密 - ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200) - .putHeader("content-type", "application/json").setBody(Body.body(buffer)); - p.complete(proxyResponse); - } else { - p.fail(h.cause()); - } - }); - }); - } +// return Future.future(p -> { +// mainWebClient.postAbs("http://localhost:9198/vertx/body").sendJson(bodyJson.toString(), h -> { +// if (h.succeeded()) { +// ProxyRequest proxyRequest = context.request(); +// // 释放资源 +// proxyRequest.release(); +// JsonObject responseData = h.result().bodyAsJsonObject(); +// // responseData.toBuffer() +// // 加密 +// String dataStr = MainSecurity.aesEncrypt(responseData.toString(), +// "dadddsdfadfadsfa33323223"); +// log.info("dataStr:{}", dataStr); +// Buffer buffer = Buffer.buffer(dataStr); +// // end 加密 +// ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200) +// .putHeader("content-type", "application/json").setBody(Body.body(buffer)); +// p.complete(proxyResponse); +// } else { +// p.fail(h.cause()); +// } +// }); +// }); +// } }); // mainHttpRouter.route().handler(sfProxyHandler); mainHttpRouter.route().handler(BodyHandler.create()).handler(sfProxyHandler); @@ -173,18 +172,18 @@ public class TestProxy { HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request))); // mock数据 -// proxy.addInterceptor(new ProxyInterceptor() { -// @Override -// public Future handleProxyRequest(ProxyContext context) { -// ProxyRequest proxyRequest = context.request(); -// // 释放资源 -// proxyRequest.release(); -// // 创建一个响应并设置参数 -// ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200) -// .putHeader("content-type", "text/plain").setBody(Body.body(Buffer.buffer("Hello World"))); -// return Future.succeededFuture(proxyResponse); -// } -// }); + proxy.addInterceptor(new ProxyInterceptor() { + @Override + public Future handleProxyRequest(ProxyContext context) { + ProxyRequest proxyRequest = context.request(); + // 释放资源 + proxyRequest.release(); + // 创建一个响应并设置参数 + ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200) + .putHeader("content-type", "text/plain").setBody(Body.body(Buffer.buffer("Hello World"))); + return Future.succeededFuture(proxyResponse); + } + }); proxy.addInterceptor(new ProxyInterceptor() { @Override public Future handleProxyRequest(ProxyContext context) { @@ -238,7 +237,7 @@ public class TestProxy { return context.sendResponse(); } }); - // mainHttpRouter.route().handler(BodyHandler.create()).handler(ProxyHandler.create(proxy)); + mainHttpRouter.route().handler(BodyHandler.create()).handler(ProxyHandler.create(proxy)); mainHttpRouter.route().handler(ProxyHandler.create(proxy)); // mainHttpRouter.route().blockingHandler(ProxyHandler.create(proxy)); // mainHttpRouter.routeWithRegex("\\/vertx/*").handler(ProxyHandler.create(proxy));