vertx加解密
This commit is contained in:
parent
4a24397f08
commit
e922dfbc4a
@ -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;// 监控指标
|
||||||
|
|
||||||
|
}
|
@ -8,8 +8,11 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class AppConfig implements Serializable {
|
public class AppConfig implements Serializable {
|
||||||
private static final long serialVersionUID = 1518165296680157119L;
|
private static final long serialVersionUID = 1518165296680157119L;
|
||||||
private String appCode;
|
private String appCode; // 应用唯一码, app访问uri添加前缀,用于网关区分多应用
|
||||||
private boolean exclusiveService; // 预留字段, 独立端口
|
private boolean exclusiveService; // 预留字段, 独立端口
|
||||||
private List<Node> nodeList;
|
private Integer exclusiveGatewayConfigId; // 独享网关配置编号
|
||||||
private List<Strategy> strategyList;
|
private EnvironmentConfig environmentConfig; // 环境配置
|
||||||
|
private List<SacService> service; // 服务
|
||||||
|
private AdvancedConfig advancedConfig; // 高级配置
|
||||||
|
private DataSecurity dataSecurity; // 数据加解密
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class DataSecurity implements Serializable {
|
public class DataSecurity implements Serializable {
|
||||||
private static final long serialVersionUID = 5034274428665340830L;
|
private static final long serialVersionUID = 5034274428665340830L;
|
||||||
|
private String key; //加密串
|
||||||
private String algorithm; // 国密加解密
|
private String algorithm; // 国密加解密
|
||||||
private String publicKey; // 公钥
|
private String publicKey; // 公钥
|
||||||
private String privateKey; // 私钥
|
private String privateKey; // 私钥
|
||||||
|
@ -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<Integer, List<Node>> environmentGroup; // 环境节点
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -8,5 +8,6 @@ import lombok.Data;
|
|||||||
public class GatewayInterface implements Serializable {
|
public class GatewayInterface implements Serializable {
|
||||||
private static final long serialVersionUID = -313734935498432381L;
|
private static final long serialVersionUID = -313734935498432381L;
|
||||||
private String uri;
|
private String uri;
|
||||||
|
private boolean uriRegular; // uri 正则
|
||||||
private String method; // 大写
|
private String method; // 大写
|
||||||
}
|
}
|
||||||
|
16
sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Router.java
Normal file
16
sf-vertx-api/src/main/java/com/sf/vertx/api/pojo/Router.java
Normal file
@ -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<String, String> headers; // 头字段
|
||||||
|
private String headerVal; // 头字段
|
||||||
|
private Integer environmentId; // 环境配置编号
|
||||||
|
|
||||||
|
}
|
@ -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<GatewayInterface> uriList; // uri列表
|
||||||
|
private Router router; // 路由
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package com.sf.vertx.api.pojo;
|
package com.sf.vertx.api.pojo;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -13,9 +12,5 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class Strategy implements Serializable {
|
public class Strategy implements Serializable {
|
||||||
private static final long serialVersionUID = -8831406773224882471L;
|
private static final long serialVersionUID = -8831406773224882471L;
|
||||||
private DataSecurity dataSecurity;
|
// 限流熔断
|
||||||
private List<GatewayInterface> gatewayInterfaceList;
|
|
||||||
private HttpClientOptionsConfig httpClientOptionsConfig; // 高并发情况,配置接口连接池
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,6 @@ public class VertxConfig implements Serializable {
|
|||||||
private static final long serialVersionUID = -1706421732809219829L;
|
private static final long serialVersionUID = -1706421732809219829L;
|
||||||
private Integer port; // 启动端口
|
private Integer port; // 启动端口
|
||||||
private VertxOptionsConfig vertxOptionsConfig;
|
private VertxOptionsConfig vertxOptionsConfig;
|
||||||
|
private HttpClientOptionsConfig httpClientOptionsConfig; // 配置Vert端口连接池
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
||||||
public class AdminApplication {
|
public class AdminApplication {
|
||||||
// 全局 ApplicationContext 实例,方便 getBean 拿到 Spring/SpringBoot 注入的类实例
|
// 全局 ApplicationContext 实例,方便 getBean 拿到 Spring/SpringBoot 注入的类实例
|
||||||
private static ApplicationContext APPLICATION_CONTEXT;
|
private static ApplicationContext APPLICATION_CONTEXT;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ public class AppConfigController {
|
|||||||
private AppConfigService appConfigService;
|
private AppConfigService appConfigService;
|
||||||
|
|
||||||
@PostMapping("/addAppConfig")
|
@PostMapping("/addAppConfig")
|
||||||
public String addAppConfig(@RequestBody AppConfig appConfig) {
|
public String addAppConfig(@RequestBody String appConfig) {
|
||||||
appConfigService.addAppConfig(appConfig);
|
appConfigService.addAppConfig(appConfig);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
144
sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandler.java
Normal file
144
sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandler.java
Normal file
@ -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}.
|
||||||
|
* <p>
|
||||||
|
* It also handles HTTP file uploads and can be used to limit body sizes.
|
||||||
|
*
|
||||||
|
* @author <a href="http://tfox.org">Tim Fox</a>
|
||||||
|
*/
|
||||||
|
@VertxGen
|
||||||
|
public interface BodyHandler extends Handler<RoutingContext> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
}
|
382
sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java
Normal file
382
sf-vertx/src/main/java/com/sf/vertx/handle/BodyHandlerImpl.java
Normal file
@ -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 <a href="http://tfox.org">Tim Fox</a>
|
||||||
|
*/
|
||||||
|
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<Buffer> {
|
||||||
|
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<FileUpload> 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<Void> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandler.java
Normal file
28
sf-vertx/src/main/java/com/sf/vertx/handle/ProxyHandler.java
Normal file
@ -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 <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
|
||||||
|
*/
|
||||||
|
|
||||||
|
@VertxGen
|
||||||
|
public interface ProxyHandler extends Handler<RoutingContext> {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -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 <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
|
||||||
|
*/
|
||||||
|
@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());
|
||||||
|
}
|
||||||
|
}
|
@ -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 <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
|
|
||||||
*/
|
|
||||||
|
|
||||||
@VertxGen
|
|
||||||
public interface SFProxyHandler extends Handler<RoutingContext> {
|
|
||||||
|
|
||||||
static SFProxyHandler create(HttpProxy httpProxy) {
|
|
||||||
return new SFProxyHandlerImpl(httpProxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SFProxyHandler create(HttpProxy httpProxy, int port, String host) {
|
|
||||||
return new SFProxyHandlerImpl(httpProxy, port, host);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <a href="mailto:emad.albloushi@gmail.com">Emad Alblueshi</a>
|
|
||||||
*/
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,7 +2,9 @@ package com.sf.vertx.init;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationArguments;
|
||||||
@ -11,23 +13,33 @@ import org.springframework.core.annotation.Order;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.sf.vertx.api.pojo.AppConfig;
|
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.Node;
|
||||||
|
import com.sf.vertx.api.pojo.SacService;
|
||||||
import com.sf.vertx.api.pojo.VertxConfig;
|
import com.sf.vertx.api.pojo.VertxConfig;
|
||||||
import com.sf.vertx.arithmetic.roundRobin.SacLoadBalancing;
|
import com.sf.vertx.arithmetic.roundRobin.SacLoadBalancing;
|
||||||
import com.sf.vertx.arithmetic.roundRobin.WeightedRoundRobin;
|
import com.sf.vertx.arithmetic.roundRobin.WeightedRoundRobin;
|
||||||
import com.sf.vertx.constans.RedisConfig;
|
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.AppConfigService;
|
||||||
|
import com.sf.vertx.service.impl.AppConfigServiceImpl;
|
||||||
|
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.Vertx;
|
import io.vertx.core.Vertx;
|
||||||
import io.vertx.core.VertxOptions;
|
import io.vertx.core.VertxOptions;
|
||||||
import io.vertx.core.http.HttpClient;
|
import io.vertx.core.http.HttpClient;
|
||||||
import io.vertx.core.http.HttpServer;
|
import io.vertx.core.http.HttpServer;
|
||||||
|
import io.vertx.core.http.HttpServerOptions;
|
||||||
import io.vertx.core.http.HttpServerRequest;
|
import io.vertx.core.http.HttpServerRequest;
|
||||||
import io.vertx.core.net.SocketAddress;
|
import io.vertx.core.net.SocketAddress;
|
||||||
import io.vertx.ext.web.Router;
|
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.HttpProxy;
|
||||||
|
import io.vertx.httpproxy.ProxyContext;
|
||||||
|
import io.vertx.httpproxy.ProxyInterceptor;
|
||||||
|
import io.vertx.httpproxy.ProxyResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@ -40,12 +52,14 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
@Order(value = 10)
|
@Order(value = 10)
|
||||||
@Component
|
@Component
|
||||||
public class DynamicBuildServer implements ApplicationRunner {
|
public class DynamicBuildServer implements ApplicationRunner {
|
||||||
|
public static final String SAC_APP_HEADER_KEY = "sacAppCode";
|
||||||
|
private static ConcurrentHashMap<Integer, SacLoadBalancing> SAC_LOADBALANCING_MAP = new ConcurrentHashMap<Integer, SacLoadBalancing>();
|
||||||
@Value("${server.vertx.server.default.port}")
|
@Value("${server.vertx.server.default.port}")
|
||||||
private Integer serverDefaultPort;
|
private Integer serverDefaultPort;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AppConfigService appConfigService;
|
private AppConfigService appConfigService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisConfig redisConfig;
|
private RedisConfig redisConfig;
|
||||||
|
|
||||||
@ -53,7 +67,6 @@ public class DynamicBuildServer implements ApplicationRunner {
|
|||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
// 初始化redis key
|
// 初始化redis key
|
||||||
redisConfig.init();
|
redisConfig.init();
|
||||||
|
|
||||||
// 加载vertx、应用配置
|
// 加载vertx、应用配置
|
||||||
appStartLoadData();
|
appStartLoadData();
|
||||||
}
|
}
|
||||||
@ -62,13 +75,17 @@ public class DynamicBuildServer implements ApplicationRunner {
|
|||||||
* 应用启动, 从redis读取配置,初始化vertx服务
|
* 应用启动, 从redis读取配置,初始化vertx服务
|
||||||
*/
|
*/
|
||||||
private void appStartLoadData() {
|
private void appStartLoadData() {
|
||||||
// 编解码线程池
|
// TODO 编解码线程池,后面优化协程等方式
|
||||||
Vertx VERTX = Vertx.vertx(new VertxOptions().setWorkerPoolSize(20));
|
Vertx VERTX = Vertx.vertx(new VertxOptions().setWorkerPoolSize(20));
|
||||||
// 创建HTTP监听
|
// 创建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);
|
Router mainHttpRouter = Router.router(VERTX);
|
||||||
VertxConfig vertxConfig = appConfigService.loadVertxConfig();
|
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 -> {
|
server.requestHandler(mainHttpRouter).listen(serverPort, h -> {
|
||||||
if (h.succeeded()) {
|
if (h.succeeded()) {
|
||||||
log.info("HTTP端口监听成功:{}", serverPort);
|
log.info("HTTP端口监听成功:{}", serverPort);
|
||||||
@ -76,52 +93,170 @@ public class DynamicBuildServer implements ApplicationRunner {
|
|||||||
log.error("HTTP端口监听失败:{}", serverPort);
|
log.error("HTTP端口监听失败:{}", serverPort);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ConcurrentHashMap<String, AppConfig> cacheAppConfig = appConfigService.loadAllConfig();
|
ConcurrentHashMap<String, AppConfig> cacheAppConfig = appConfigService.loadAllConfig();
|
||||||
for (String appCode : cacheAppConfig.keySet()) {
|
// HttpClientOptions clientOptions = new HttpClientOptions();
|
||||||
AppConfig appConfig = cacheAppConfig.get(appCode);
|
// clientOptions.setMaxPoolSize(20); // 最大连接池大小
|
||||||
// 负载均衡算法
|
// clientOptions.setConnectTimeout(5000); // 连接超时 毫秒
|
||||||
// 轮训
|
// clientOptions.setHttp2KeepAliveTimeout(1);
|
||||||
SacLoadBalancing sacLoadBalancing = roundRobin(appConfig.getNodeList());
|
// clientOptions.setIdleTimeout(1000); // 连接空闲超时 毫秒
|
||||||
|
// HttpClient proxyClient = VERTX.createHttpClient(clientOptions);
|
||||||
|
HttpClient proxyClient = VERTX.createHttpClient();
|
||||||
// 有策略
|
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
||||||
if (appConfig.getStrategyList() != null && appConfig.getStrategyList().size() > 0) {
|
proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(cacheAppConfig, request)));
|
||||||
|
proxy.addInterceptor(new ProxyInterceptor() {
|
||||||
} else {
|
@Override
|
||||||
// 无策略,直接走反向代理
|
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
||||||
// HttpClientOptions clientOptions = new HttpClientOptions();
|
// 修改uri context.request().setURI();
|
||||||
// clientOptions.setMaxPoolSize(20); // 最大连接池大小
|
String sacAppHeaderKey = context.request().headers().get(DynamicBuildServer.SAC_APP_HEADER_KEY);
|
||||||
// clientOptions.setConnectTimeout(5000); // 连接超时 毫秒
|
log.info("addInterceptor uri appCode:{}", sacAppHeaderKey);
|
||||||
// clientOptions.setHttp2KeepAliveTimeout(1);
|
// 判断是否需要加解析
|
||||||
// clientOptions.setIdleTimeout(1000); // 连接空闲超时 毫秒
|
if (AppConfigServiceImpl.appDataSecurity(sacAppHeaderKey)) {
|
||||||
// HttpClient proxyClient = VERTX.createHttpClient(clientOptions);
|
|
||||||
|
//String data = decode(null, sacAppHeaderKey);
|
||||||
HttpClient proxyClient = VERTX.createHttpClient();
|
|
||||||
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
}
|
||||||
proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(sacLoadBalancing, request)));
|
return context.sendRequest();
|
||||||
mainHttpRouter.route().handler(ProxyHandler.create(proxy));
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
// mainHttpRouter.route().handler(ProxyHandler.create(proxy));
|
||||||
|
WebClient mainWebClient = WebClient.create(VERTX);
|
||||||
public SocketAddress resolveOriginAddress(SacLoadBalancing sacLoadBalancing, HttpServerRequest request) {
|
mainHttpRouter.route().handler(BodyHandler.create()).handler(ProxyHandler.create(mainWebClient,proxy));
|
||||||
// TODO 区分https、http
|
|
||||||
Node node = sacLoadBalancing.selectNode();
|
|
||||||
SocketAddress socketAddress = SocketAddress.inetSocketAddress(node.getPort(), node.getIp());
|
|
||||||
log.info("负载均衡跳转地址:{}", socketAddress.host() +";"+socketAddress.port());
|
|
||||||
return socketAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SocketAddress resolveOriginAddress(ConcurrentHashMap<String, AppConfig> cacheAppConfig,
|
||||||
private SacLoadBalancing roundRobin(List<Node> nodeList) {
|
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<Node> 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<Node> nodeList) {
|
||||||
WeightedRoundRobin weightedRoundRobin = new WeightedRoundRobin();
|
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.setWeight(weight);
|
||||||
node.setCurrentWeight(weight);
|
node.setCurrentWeight(weight);
|
||||||
node.setEffectiveWeight(weight);
|
node.setEffectiveWeight(weight);
|
||||||
weight++;
|
|
||||||
WeightedRoundRobin.totalWeight += node.getEffectiveWeight();
|
WeightedRoundRobin.totalWeight += node.getEffectiveWeight();
|
||||||
}
|
}
|
||||||
weightedRoundRobin.init(nodeList);
|
weightedRoundRobin.init(nodeList);
|
||||||
|
@ -8,7 +8,7 @@ import com.sf.vertx.api.pojo.VertxConfig;
|
|||||||
public interface AppConfigService {
|
public interface AppConfigService {
|
||||||
ConcurrentHashMap<String, AppConfig> loadAllConfig();
|
ConcurrentHashMap<String, AppConfig> loadAllConfig();
|
||||||
|
|
||||||
void addAppConfig(AppConfig appConfig);
|
void addAppConfig(String appConfig);
|
||||||
|
|
||||||
void deleteAppConfig(AppConfig appConfig);
|
void deleteAppConfig(AppConfig appConfig);
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.sf.vertx.service.impl;
|
package com.sf.vertx.service.impl;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@ -12,8 +11,8 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.alibaba.fastjson2.TypeReference;
|
||||||
import com.sf.vertx.api.pojo.AppConfig;
|
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.api.pojo.VertxConfig;
|
||||||
import com.sf.vertx.constans.RedisConfig;
|
import com.sf.vertx.constans.RedisConfig;
|
||||||
import com.sf.vertx.service.AppConfigService;
|
import com.sf.vertx.service.AppConfigService;
|
||||||
@ -27,26 +26,24 @@ public class AppConfigServiceImpl implements AppConfigService {
|
|||||||
private String vertxEnvironment;
|
private String vertxEnvironment;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<String, String> redisTemplate;
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
|
private static final ConcurrentHashMap<String, AppConfig> cacheAppConfig = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean appDataSecurity(String appCode) {
|
||||||
|
return cacheAppConfig.get(appCode) != null && cacheAppConfig.get(appCode).getDataSecurity() != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* 从redis加载数据
|
* 从redis加载数据
|
||||||
*/
|
*/
|
||||||
public ConcurrentHashMap<String, AppConfig> loadAllConfig() {
|
public ConcurrentHashMap<String, AppConfig> loadAllConfig() {
|
||||||
ConcurrentHashMap<String, AppConfig> cacheAppConfig = new ConcurrentHashMap<>();
|
|
||||||
// 获取所有app列表
|
|
||||||
Set<String> set = redisTemplate.opsForZSet().range(RedisConfig.APP_CONFIG_SET_KEY, 0, -1);
|
Set<String> set = redisTemplate.opsForZSet().range(RedisConfig.APP_CONFIG_SET_KEY, 0, -1);
|
||||||
for(String appCode : set) {
|
for(String appCode : set) {
|
||||||
String appCodeKey = RedisConfig.APP_CONFIG_PREFIX_KEY + ":" + appCode;
|
String appCodeKey = RedisConfig.APP_CONFIG_PREFIX_KEY + ":" + appCode;
|
||||||
String appCodeValue = redisTemplate.opsForValue().get(appCodeKey);
|
String appCodeValue = redisTemplate.opsForValue().get(appCodeKey);
|
||||||
if(StringUtils.isNotBlank(appCodeValue)) {
|
if(StringUtils.isNotBlank(appCodeValue)) {
|
||||||
AppConfig appConfig = JSON.parseObject(appCodeValue, AppConfig.class);
|
AppConfig appConfig = JSON.parseObject(appCodeValue, new TypeReference<AppConfig>() {});
|
||||||
cacheAppConfig.put(appCode, appConfig);
|
cacheAppConfig.put(appCode, appConfig);
|
||||||
|
|
||||||
//JSONObject jsonObject = JSONObject.parseObject(appCodeValue);//从请求体里获得jsonObject
|
|
||||||
//String oldGoodsStorageModes = jsonObject.getString("nodeList");//解析成字符串
|
|
||||||
//字符串转list
|
|
||||||
//List<Node> oldGoodsStoragemodes = JSON.parseArray(oldGoodsStorageModes,Node.class);
|
|
||||||
//log.info("oldGoodsStoragemodes:{}", JSON.toJSONString(oldGoodsStoragemodes));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("cacheAppConfig:{}", JSON.toJSONString(cacheAppConfig));
|
log.info("cacheAppConfig:{}", JSON.toJSONString(cacheAppConfig));
|
||||||
@ -67,10 +64,11 @@ public class AppConfigServiceImpl implements AppConfigService {
|
|||||||
* 新增、修改
|
* 新增、修改
|
||||||
* @param appConfig
|
* @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);
|
redisTemplate.opsForZSet().add(RedisConfig.APP_CONFIG_SET_KEY, appConfig.getAppCode(), 0);
|
||||||
String appCodeKey = RedisConfig.APP_CONFIG_PREFIX_KEY + ":" + appConfig.getAppCode();
|
String appCodeKey = RedisConfig.APP_CONFIG_PREFIX_KEY + ":" + appConfig.getAppCode();
|
||||||
redisTemplate.opsForValue().set(appCodeKey, JSONObject.toJSONString(appConfig));
|
redisTemplate.opsForValue().set(appCodeKey, appConfigStr);
|
||||||
|
|
||||||
// 发送redis队列,vertx处理
|
// 发送redis队列,vertx处理
|
||||||
//String queue = RedisConfig.VETX_ENVIRONMENT_KEY+vertxEnvironment+":list";
|
//String queue = RedisConfig.VETX_ENVIRONMENT_KEY+vertxEnvironment+":list";
|
||||||
|
@ -4,7 +4,7 @@ server:
|
|||||||
environment: dev
|
environment: dev
|
||||||
server:
|
server:
|
||||||
default:
|
default:
|
||||||
port: 9099
|
port: 80
|
||||||
# 服务器的HTTP端口,默认为8080
|
# 服务器的HTTP端口,默认为8080
|
||||||
port: 5566
|
port: 5566
|
||||||
servlet:
|
servlet:
|
||||||
@ -38,9 +38,9 @@ spring:
|
|||||||
# redis 配置
|
# redis 配置
|
||||||
redis:
|
redis:
|
||||||
# 地址
|
# 地址
|
||||||
host: 192.168.1.23
|
host: 127.0.0.1 #192.168.1.23
|
||||||
# 端口,默认为6379
|
# 端口,默认为6379
|
||||||
port: 22002
|
port: 6379 #22002
|
||||||
# 数据库索引
|
# 数据库索引
|
||||||
database: 0
|
database: 0
|
||||||
# 密码
|
# 密码
|
||||||
|
24
sf-vertx/src/test/java/com/sf/vertx/PatternTest.java
Normal file
24
sf-vertx/src/test/java/com/sf/vertx/PatternTest.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.sf.vertx.handle.SFProxyHandler;
|
import com.sf.vertx.handle.ProxyHandlerImpl;
|
||||||
import com.sf.vertx.handle.SFProxyHandlerImpl;
|
|
||||||
import com.sf.vertx.security.MainSecurity;
|
import com.sf.vertx.security.MainSecurity;
|
||||||
|
|
||||||
import io.vertx.core.AsyncResult;
|
import io.vertx.core.AsyncResult;
|
||||||
@ -80,45 +79,45 @@ public class TestProxy {
|
|||||||
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
||||||
|
|
||||||
proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request)));
|
proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request)));
|
||||||
SFProxyHandler sfProxyHandler = SFProxyHandler.create(proxy);
|
ProxyHandler sfProxyHandler = ProxyHandler.create(proxy);
|
||||||
WebClient mainWebClient = WebClient.create(VERTX);
|
WebClient mainWebClient = WebClient.create(VERTX);
|
||||||
proxy.addInterceptor(new ProxyInterceptor() {
|
proxy.addInterceptor(new ProxyInterceptor() {
|
||||||
@Override
|
// @Override
|
||||||
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
// public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
||||||
SFProxyHandlerImpl sfProxyHandlerImpl = (SFProxyHandlerImpl) sfProxyHandler;
|
// ProxyHandlerImpl sfProxyHandlerImpl = (ProxyHandlerImpl) sfProxyHandler;
|
||||||
// String body = sfProxyHandlerImpl.getCtx().getBodyAsString();
|
// String body = sfProxyHandlerImpl.getCtx().getBodyAsString();
|
||||||
// log.info("ctx.getBodyAsJson():{}", body);
|
// log.info("ctx.getBodyAsJson():{}", body);
|
||||||
JsonObject bodyJson = sfProxyHandlerImpl.getCtx().getBodyAsJson();
|
//JsonObject bodyJson = sfProxyHandlerImpl.getCtx().getBodyAsJson();
|
||||||
HttpServerRequest HttpServerRequest = context.request().proxiedRequest();
|
//HttpServerRequest HttpServerRequest = context.request().proxiedRequest();
|
||||||
// 解密
|
// 解密
|
||||||
String data = MainSecurity.aesDecrypt(bodyJson.getString("data"), "dadddsdfadfadsfa33323223");
|
//String data = MainSecurity.aesDecrypt(bodyJson.getString("data"), "dadddsdfadfadsfa33323223");
|
||||||
bodyJson.put("data", data);
|
//bodyJson.put("data", data);
|
||||||
// end解密
|
// end解密
|
||||||
// uri重写
|
// uri重写
|
||||||
// context.request().setURI("/vertx/body");
|
// context.request().setURI("/vertx/body");
|
||||||
return Future.future(p -> {
|
// return Future.future(p -> {
|
||||||
mainWebClient.postAbs("http://localhost:9198/vertx/body").sendJson(bodyJson.toString(), h -> {
|
// mainWebClient.postAbs("http://localhost:9198/vertx/body").sendJson(bodyJson.toString(), h -> {
|
||||||
if (h.succeeded()) {
|
// if (h.succeeded()) {
|
||||||
ProxyRequest proxyRequest = context.request();
|
// ProxyRequest proxyRequest = context.request();
|
||||||
// 释放资源
|
// // 释放资源
|
||||||
proxyRequest.release();
|
// proxyRequest.release();
|
||||||
JsonObject responseData = h.result().bodyAsJsonObject();
|
// JsonObject responseData = h.result().bodyAsJsonObject();
|
||||||
// responseData.toBuffer()
|
// // responseData.toBuffer()
|
||||||
// 加密
|
// // 加密
|
||||||
String dataStr = MainSecurity.aesEncrypt(responseData.toString(),
|
// String dataStr = MainSecurity.aesEncrypt(responseData.toString(),
|
||||||
"dadddsdfadfadsfa33323223");
|
// "dadddsdfadfadsfa33323223");
|
||||||
log.info("dataStr:{}", dataStr);
|
// log.info("dataStr:{}", dataStr);
|
||||||
Buffer buffer = Buffer.buffer(dataStr);
|
// Buffer buffer = Buffer.buffer(dataStr);
|
||||||
// end 加密
|
// // end 加密
|
||||||
ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
|
// ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
|
||||||
.putHeader("content-type", "application/json").setBody(Body.body(buffer));
|
// .putHeader("content-type", "application/json").setBody(Body.body(buffer));
|
||||||
p.complete(proxyResponse);
|
// p.complete(proxyResponse);
|
||||||
} else {
|
// } else {
|
||||||
p.fail(h.cause());
|
// p.fail(h.cause());
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
});
|
||||||
// mainHttpRouter.route().handler(sfProxyHandler);
|
// mainHttpRouter.route().handler(sfProxyHandler);
|
||||||
mainHttpRouter.route().handler(BodyHandler.create()).handler(sfProxyHandler);
|
mainHttpRouter.route().handler(BodyHandler.create()).handler(sfProxyHandler);
|
||||||
@ -173,18 +172,18 @@ public class TestProxy {
|
|||||||
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
|
||||||
proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request)));
|
proxy.originSelector(request -> Future.succeededFuture(resolveOriginAddress(request)));
|
||||||
// mock数据
|
// mock数据
|
||||||
// proxy.addInterceptor(new ProxyInterceptor() {
|
proxy.addInterceptor(new ProxyInterceptor() {
|
||||||
// @Override
|
@Override
|
||||||
// public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
||||||
// ProxyRequest proxyRequest = context.request();
|
ProxyRequest proxyRequest = context.request();
|
||||||
// // 释放资源
|
// 释放资源
|
||||||
// proxyRequest.release();
|
proxyRequest.release();
|
||||||
// // 创建一个响应并设置参数
|
// 创建一个响应并设置参数
|
||||||
// ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
|
ProxyResponse proxyResponse = proxyRequest.response().setStatusCode(200)
|
||||||
// .putHeader("content-type", "text/plain").setBody(Body.body(Buffer.buffer("Hello World")));
|
.putHeader("content-type", "text/plain").setBody(Body.body(Buffer.buffer("Hello World")));
|
||||||
// return Future.succeededFuture(proxyResponse);
|
return Future.succeededFuture(proxyResponse);
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
proxy.addInterceptor(new ProxyInterceptor() {
|
proxy.addInterceptor(new ProxyInterceptor() {
|
||||||
@Override
|
@Override
|
||||||
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
|
||||||
@ -238,7 +237,7 @@ public class TestProxy {
|
|||||||
return context.sendResponse();
|
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().handler(ProxyHandler.create(proxy));
|
||||||
// mainHttpRouter.route().blockingHandler(ProxyHandler.create(proxy));
|
// mainHttpRouter.route().blockingHandler(ProxyHandler.create(proxy));
|
||||||
// mainHttpRouter.routeWithRegex("\\/vertx/*").handler(ProxyHandler.create(proxy));
|
// mainHttpRouter.routeWithRegex("\\/vertx/*").handler(ProxyHandler.create(proxy));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user