网关逻辑调整
This commit is contained in:
parent
3af1185522
commit
e80cd14064
@ -76,6 +76,7 @@
|
|||||||
<groupId>com.smarterFramework</groupId>
|
<groupId>com.smarterFramework</groupId>
|
||||||
<artifactId>sf-service</artifactId>
|
<artifactId>sf-service</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -9,12 +9,10 @@ import com.sf.service.index.utils.AppUtils;
|
|||||||
import com.sf.service.gateway.domain.*;
|
import com.sf.service.gateway.domain.*;
|
||||||
import com.sf.service.gateway.domain.dto.QueryGatewayServerDTO;
|
import com.sf.service.gateway.domain.dto.QueryGatewayServerDTO;
|
||||||
import com.sf.service.gateway.domain.dto.UpdateDataStatusDTO;
|
import com.sf.service.gateway.domain.dto.UpdateDataStatusDTO;
|
||||||
import com.sf.service.gateway.domain.vo.GatewayInterfaceInfoListVO;
|
|
||||||
import com.sf.service.gateway.domain.vo.GatewayServerDetailedVO;
|
import com.sf.service.gateway.domain.vo.GatewayServerDetailedVO;
|
||||||
import com.sf.service.gateway.domain.vo.GatewayServerListVO;
|
import com.sf.service.gateway.domain.vo.GatewayServerListVO;
|
||||||
import com.sf.service.gateway.domain.vo.GatewayStrategyListVO;
|
|
||||||
import com.sf.service.gateway.enums.GatewayDataStatus;
|
import com.sf.service.gateway.enums.GatewayDataStatus;
|
||||||
import com.sf.service.gateway.enums.GatewayServiceModel;
|
import com.sf.vertx.enums.GatewayServiceModel;
|
||||||
import com.sf.service.gateway.service.IGatewayInterfaceInfoService;
|
import com.sf.service.gateway.service.IGatewayInterfaceInfoService;
|
||||||
import com.sf.service.gateway.service.IGatewayRouteService;
|
import com.sf.service.gateway.service.IGatewayRouteService;
|
||||||
import com.sf.service.gateway.service.IGatewayServerService;
|
import com.sf.service.gateway.service.IGatewayServerService;
|
||||||
|
@ -2,7 +2,7 @@ package com.sf.service.gateway.domain.dto;
|
|||||||
|
|
||||||
import com.sf.common.annotation.Excel;
|
import com.sf.common.annotation.Excel;
|
||||||
import com.sf.service.gateway.domain.GatewayRoute;
|
import com.sf.service.gateway.domain.GatewayRoute;
|
||||||
import com.sf.service.gateway.enums.GatewayRouteType;
|
import com.sf.vertx.enums.GatewayRouteType;
|
||||||
import com.sf.service.gateway.enums.RequestProtocol;
|
import com.sf.service.gateway.enums.RequestProtocol;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
@ -3,14 +3,10 @@ package com.sf.service.gateway.domain.vo;
|
|||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.sf.common.annotation.Excel;
|
import com.sf.common.annotation.Excel;
|
||||||
import com.sf.service.gateway.domain.GatewayRoute;
|
import com.sf.service.gateway.domain.GatewayRoute;
|
||||||
import com.sf.service.gateway.enums.GatewayRouteType;
|
|
||||||
import com.sf.service.gateway.enums.RequestProtocol;
|
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import javax.validation.constraints.Size;
|
import javax.validation.constraints.Size;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -2,7 +2,7 @@ package com.sf.service.gateway.domain.vo;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import com.sf.service.gateway.domain.*;
|
import com.sf.service.gateway.domain.*;
|
||||||
import com.sf.service.gateway.enums.GatewayServiceModel;
|
import com.sf.vertx.enums.GatewayServiceModel;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
package com.sf.service.gateway.domain.vo;
|
package com.sf.service.gateway.domain.vo;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import com.sf.common.annotation.Excel;
|
|
||||||
import com.sf.common.core.domain.BaseEntity;
|
|
||||||
import com.sf.service.gateway.domain.GatewayRoute;
|
import com.sf.service.gateway.domain.GatewayRoute;
|
||||||
import com.sf.service.gateway.domain.GatewayServer;
|
import com.sf.service.gateway.domain.GatewayServer;
|
||||||
import com.sf.service.gateway.enums.GatewayServiceModel;
|
import com.sf.vertx.enums.GatewayServiceModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.hibernate.validator.constraints.URL;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import javax.validation.constraints.Pattern;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
package com.sf.service.gateway.enums;
|
|
||||||
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 网关路由类型
|
|
||||||
*
|
|
||||||
* @author zoukun
|
|
||||||
*/
|
|
||||||
public enum GatewayRouteType
|
|
||||||
{
|
|
||||||
WEIGHT_ROUTE("WEIGHT_ROUTE", "权重路由策略"),
|
|
||||||
HEADER_ROUTE("HEADER_ROUTE", "请求头路由策略"),
|
|
||||||
;
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String info;
|
|
||||||
|
|
||||||
GatewayRouteType(String code, String info)
|
|
||||||
{
|
|
||||||
this.code = code;
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode()
|
|
||||||
{
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInfo()
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GatewayRouteType getByCode(String code){
|
|
||||||
if (StringUtils.hasText(code)) {
|
|
||||||
for (GatewayRouteType value : GatewayRouteType.values()) {
|
|
||||||
if (value.code.equals(code)){
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package com.sf.service.gateway.enums;
|
|
||||||
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 网关服务模式
|
|
||||||
*
|
|
||||||
* @author zoukun
|
|
||||||
*/
|
|
||||||
public enum GatewayServiceModel
|
|
||||||
{
|
|
||||||
NORMAL("NORMAL", "普通模式"),
|
|
||||||
ROUTE("ROUTE", "路由模式"),
|
|
||||||
;
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String info;
|
|
||||||
|
|
||||||
GatewayServiceModel(String code, String info)
|
|
||||||
{
|
|
||||||
this.code = code;
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode()
|
|
||||||
{
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInfo()
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GatewayServiceModel getByCode(String code){
|
|
||||||
if (StringUtils.hasText(code)) {
|
|
||||||
for (GatewayServiceModel value : GatewayServiceModel.values()) {
|
|
||||||
if (value.code.equals(code)){
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package com.sf.service.gateway.enums;
|
|
||||||
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 网关服务类型
|
|
||||||
*
|
|
||||||
* @author zoukun
|
|
||||||
*/
|
|
||||||
public enum GatewayServiceType
|
|
||||||
{
|
|
||||||
SAC("SAC", "SAC规范服务"),
|
|
||||||
OPEN("OPEN", "开放服务"),
|
|
||||||
;
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String info;
|
|
||||||
|
|
||||||
GatewayServiceType(String code, String info)
|
|
||||||
{
|
|
||||||
this.code = code;
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode()
|
|
||||||
{
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInfo()
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GatewayServiceType getByCode(String code){
|
|
||||||
if (StringUtils.hasText(code)) {
|
|
||||||
for (GatewayServiceType value : GatewayServiceType.values()) {
|
|
||||||
if (value.code.equals(code)){
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ import com.sf.common.utils.SecurityUtils;
|
|||||||
import com.sf.service.gateway.domain.*;
|
import com.sf.service.gateway.domain.*;
|
||||||
import com.sf.service.gateway.enums.EncryptionAlgorithm;
|
import com.sf.service.gateway.enums.EncryptionAlgorithm;
|
||||||
import com.sf.service.gateway.enums.GatewayDataStatus;
|
import com.sf.service.gateway.enums.GatewayDataStatus;
|
||||||
import com.sf.service.gateway.enums.GatewayServiceModel;
|
import com.sf.vertx.enums.GatewayServiceModel;
|
||||||
import com.sf.service.gateway.enums.GatewayStrategyType;
|
import com.sf.service.gateway.enums.GatewayStrategyType;
|
||||||
import com.sf.service.gateway.mapper.GatewayConfigMapper;
|
import com.sf.service.gateway.mapper.GatewayConfigMapper;
|
||||||
import com.sf.service.gateway.service.*;
|
import com.sf.service.gateway.service.*;
|
||||||
|
@ -17,6 +17,8 @@ import com.sf.service.gateway.enums.*;
|
|||||||
import com.sf.service.gateway.mapper.GatewayRouteMapper;
|
import com.sf.service.gateway.mapper.GatewayRouteMapper;
|
||||||
import com.sf.service.gateway.service.IGatewayRouteService;
|
import com.sf.service.gateway.service.IGatewayRouteService;
|
||||||
import com.sf.service.gateway.service.IGatewayServerService;
|
import com.sf.service.gateway.service.IGatewayServerService;
|
||||||
|
import com.sf.vertx.enums.GatewayRouteType;
|
||||||
|
import com.sf.vertx.enums.GatewayServiceModel;
|
||||||
import com.sf.vertx.enums.MatchType;
|
import com.sf.vertx.enums.MatchType;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -10,8 +10,8 @@ import com.sf.common.utils.URLUtils;
|
|||||||
import com.sf.service.gateway.domain.GatewayInterfaceInfo;
|
import com.sf.service.gateway.domain.GatewayInterfaceInfo;
|
||||||
import com.sf.service.gateway.domain.GatewayServer;
|
import com.sf.service.gateway.domain.GatewayServer;
|
||||||
import com.sf.service.gateway.enums.GatewayDataStatus;
|
import com.sf.service.gateway.enums.GatewayDataStatus;
|
||||||
import com.sf.service.gateway.enums.GatewayServiceModel;
|
import com.sf.vertx.enums.GatewayServiceModel;
|
||||||
import com.sf.service.gateway.enums.GatewayServiceType;
|
import com.sf.vertx.enums.GatewayServiceType;
|
||||||
import com.sf.vertx.enums.RequestMethod;
|
import com.sf.vertx.enums.RequestMethod;
|
||||||
import com.sf.service.gateway.mapper.GatewayServerMapper;
|
import com.sf.service.gateway.mapper.GatewayServerMapper;
|
||||||
import com.sf.service.gateway.service.IGatewayInterfaceInfoService;
|
import com.sf.service.gateway.service.IGatewayInterfaceInfoService;
|
||||||
|
119
sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayError.java
Normal file
119
sf-vertx-api/src/main/java/com/sf/vertx/enums/GatewayError.java
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package com.sf.vertx.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VertX网关错误
|
||||||
|
*
|
||||||
|
* @author zoukun
|
||||||
|
*/
|
||||||
|
public enum GatewayError {
|
||||||
|
// CLIENT ERROR
|
||||||
|
BAD_REQUEST(400, "Bad Request", ErrorType.CLIENT_ERROR),
|
||||||
|
UNAUTHORIZED(401, "Unauthorized", ErrorType.CLIENT_ERROR),
|
||||||
|
FORBIDDEN(403, "Forbidden", ErrorType.CLIENT_ERROR),
|
||||||
|
NOT_FOUND(404, "Not Found", ErrorType.CLIENT_ERROR),
|
||||||
|
METHOD_NOT_ALLOWED(405, "Method Not Allowed", ErrorType.CLIENT_ERROR),
|
||||||
|
NOT_ACCEPTABLE(406, "Not Acceptable", ErrorType.CLIENT_ERROR),
|
||||||
|
PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required", ErrorType.CLIENT_ERROR),
|
||||||
|
REQUEST_TIMEOUT(408, "Request Timeout", ErrorType.CLIENT_ERROR),
|
||||||
|
CONFLICT(409, "Conflict", ErrorType.CLIENT_ERROR),
|
||||||
|
GONE(410, "Gone", ErrorType.CLIENT_ERROR),
|
||||||
|
LENGTH_REQUIRED(411, "Length Required", ErrorType.CLIENT_ERROR),
|
||||||
|
PRECONDITION_FAILED(412, "Precondition Failed", ErrorType.CLIENT_ERROR),
|
||||||
|
PAYLOAD_TOO_LARGE(413, "Payload Too Large", ErrorType.CLIENT_ERROR),
|
||||||
|
URI_TOO_LONG(414, "URI Too Long", ErrorType.CLIENT_ERROR),
|
||||||
|
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type", ErrorType.CLIENT_ERROR),
|
||||||
|
REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable", ErrorType.CLIENT_ERROR),
|
||||||
|
EXPECTATION_FAILED(417, "Expectation Failed", ErrorType.CLIENT_ERROR),
|
||||||
|
UNPROCESSABLE_ENTITY(422, "Unprocessable Entity", ErrorType.CLIENT_ERROR),
|
||||||
|
LOCKED(423, "Locked", ErrorType.CLIENT_ERROR),
|
||||||
|
FAILED_DEPENDENCY(424, "Failed Dependency", ErrorType.CLIENT_ERROR),
|
||||||
|
TOO_EARLY(425, "Too Early", ErrorType.CLIENT_ERROR),
|
||||||
|
UPGRADE_REQUIRED(426, "Upgrade Required", ErrorType.CLIENT_ERROR),
|
||||||
|
PRECONDITION_REQUIRED(428, "Precondition Required", ErrorType.CLIENT_ERROR),
|
||||||
|
TOO_MANY_REQUESTS(429, "Too Many Requests", ErrorType.CLIENT_ERROR),
|
||||||
|
REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large", ErrorType.CLIENT_ERROR),
|
||||||
|
UNAVAILABLE_FOR_LEGAL_REASONS(451, "Unavailable For Legal Reasons", ErrorType.CLIENT_ERROR),
|
||||||
|
|
||||||
|
// SERVER_ERROR
|
||||||
|
INTERNAL_SERVER_ERROR(500, "Internal Server Error", ErrorType.SERVER_ERROR),
|
||||||
|
NOT_IMPLEMENTED(501, "Not Implemented", ErrorType.SERVER_ERROR),
|
||||||
|
BAD_GATEWAY(502, "Bad Gateway", ErrorType.SERVER_ERROR),
|
||||||
|
SERVICE_UNAVAILABLE(503, "Service Unavailable", ErrorType.SERVER_ERROR),
|
||||||
|
GATEWAY_TIMEOUT(504, "Gateway Timeout", ErrorType.SERVER_ERROR),
|
||||||
|
HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported", ErrorType.SERVER_ERROR),
|
||||||
|
INSUFFICIENT_STORAGE(507, "Insufficient Storage", ErrorType.SERVER_ERROR),
|
||||||
|
NOT_EXTENDED(510, "Not Extended", ErrorType.SERVER_ERROR),
|
||||||
|
NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required", ErrorType.SERVER_ERROR),
|
||||||
|
|
||||||
|
// SERVICE_ERROR
|
||||||
|
DEFAULT_SERVICE_ERROR(10000, "Service request failed, please try again later", ErrorType.SERVICE_ERROR), // 默认业务错误提示
|
||||||
|
APP_ACCESS_PROHIBITED(10001, "应用禁止访问,请联系管理员", ErrorType.SERVICE_ERROR),
|
||||||
|
APP_SERVICE_NOT_FOUND(10002, "APP service not found", ErrorType.SERVICE_ERROR),
|
||||||
|
API_SERVICE_NOT_FOUND(10003, "API service not found", ErrorType.SERVICE_ERROR),
|
||||||
|
PARAMETER_TRANSFER_ERROR(10010, "参数传递错误", ErrorType.SERVICE_ERROR),
|
||||||
|
UNABLE_TO_FIND_ROUTING_ADDRESS(10011, "无法找到路由地址", ErrorType.SERVICE_ERROR),
|
||||||
|
UNABLE_TO_FIND_MATCHING_ENCRYPTION_ALGORITHM(10012, "无法找到匹配的加解密算法", ErrorType.SERVICE_ERROR),
|
||||||
|
UNABLE_TO_FIND_MATCHING_CIRCUIT_BREAKER_STRATEGY(10013, "无法找到匹配的熔断策略", ErrorType.SERVICE_ERROR),
|
||||||
|
REVERSE_PROXY_EXECUTION_ERROR(10014, "反向代理执行错误", ErrorType.SERVICE_ERROR),
|
||||||
|
REQUEST_URL_RESTRICTED_BY_FLOW(10015, "请求url被限流", ErrorType.SERVICE_ERROR),
|
||||||
|
REQUEST_URL_IS_BROKEN(10016, "请求url被熔断", ErrorType.SERVICE_ERROR),
|
||||||
|
APP_REQUEST_URL_RESTRICTED_BY_FLOW(10017, "应用请求url被限流", ErrorType.SERVICE_ERROR),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
private final String reasonPhrase;
|
||||||
|
|
||||||
|
private final ErrorType errorType;
|
||||||
|
|
||||||
|
GatewayError(int code, String reasonPhrase, ErrorType errorType) {
|
||||||
|
this.code = code;
|
||||||
|
this.reasonPhrase = reasonPhrase;
|
||||||
|
this.errorType = errorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorType getErrorType() {
|
||||||
|
return errorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReasonPhrase() {
|
||||||
|
return reasonPhrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GatewayError getByCode(int code) {
|
||||||
|
for (GatewayError value : GatewayError.values()) {
|
||||||
|
if (value.code == code) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关错误类型
|
||||||
|
*/
|
||||||
|
public enum ErrorType {
|
||||||
|
|
||||||
|
CLIENT_ERROR(4),
|
||||||
|
SERVER_ERROR(5),
|
||||||
|
/**
|
||||||
|
* 业务错误,建议业务错误返回HTTP状态码为200,业务码放在返回信息当中。
|
||||||
|
*/
|
||||||
|
SERVICE_ERROR(10),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
ErrorType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int value() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.sf.vertx.enums;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关路由类型
|
||||||
|
*
|
||||||
|
* @author zoukun
|
||||||
|
*/
|
||||||
|
public enum GatewayRouteType {
|
||||||
|
WEIGHT_ROUTE("WEIGHT_ROUTE", "权重路由策略"),
|
||||||
|
HEADER_ROUTE("HEADER_ROUTE", "请求头路由策略"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
GatewayRouteType(String code, String info) {
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GatewayRouteType getByCode(String code) {
|
||||||
|
for (GatewayRouteType value : GatewayRouteType.values()) {
|
||||||
|
if (value.code.equals(code)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.sf.vertx.enums;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关服务模式
|
||||||
|
*
|
||||||
|
* @author zoukun
|
||||||
|
*/
|
||||||
|
public enum GatewayServiceModel {
|
||||||
|
NORMAL("NORMAL", "普通模式"),
|
||||||
|
ROUTE("ROUTE", "路由模式"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
GatewayServiceModel(String code, String info) {
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GatewayServiceModel getByCode(String code) {
|
||||||
|
for (GatewayServiceModel value : GatewayServiceModel.values()) {
|
||||||
|
if (value.code.equals(code)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.sf.vertx.enums;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关服务类型
|
||||||
|
*
|
||||||
|
* @author zoukun
|
||||||
|
*/
|
||||||
|
public enum GatewayServiceType {
|
||||||
|
SAC("SAC", "SAC规范服务"),
|
||||||
|
OPEN("OPEN", "开放服务"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String info;
|
||||||
|
|
||||||
|
GatewayServiceType(String code, String info) {
|
||||||
|
this.code = code;
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GatewayServiceType getByCode(String code) {
|
||||||
|
for (GatewayServiceType value : GatewayServiceType.values()) {
|
||||||
|
if (value.code.equals(code)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -226,6 +226,11 @@
|
|||||||
<groupId>io.vertx</groupId>
|
<groupId>io.vertx</groupId>
|
||||||
<artifactId>vertx-consul-client</artifactId>
|
<artifactId>vertx-consul-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.studio</groupId>
|
||||||
|
<artifactId>org.apache.commons.codec</artifactId>
|
||||||
|
<version>1.8</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.sf.vertx.constans;
|
||||||
|
|
||||||
|
public class SACConstants {
|
||||||
|
|
||||||
|
public static final String CACHE_KEY_CONNECTOR = ":";
|
||||||
|
|
||||||
|
public static final String APP_CONFIG = "appConfig";
|
||||||
|
|
||||||
|
public static final String API_CONFIG = "apiConfig";
|
||||||
|
|
||||||
|
public static final String API_SERVICE_TYPE = "apiServiceType";
|
||||||
|
|
||||||
|
public static final String CIRCUIT_BREAKER = "CIRCUIT_BREAKER";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务码 key
|
||||||
|
*/
|
||||||
|
public static final String GATEWAY_SERVICE_CODE = "serviceCode";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
package com.sf.vertx.constans;
|
|
||||||
|
|
||||||
public class SacConstans {
|
|
||||||
public static final String CACHE_KEY_CONNECTOR = ":";
|
|
||||||
public static final String CIRCUIT_BREAKER = "CIRCUIT_BREAKER";
|
|
||||||
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
package com.sf.vertx.constans;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import io.vertx.core.json.JsonObject;
|
|
||||||
|
|
||||||
public class SacErrorCode {
|
|
||||||
public static final Integer DEFAULT_ERROR_CODE = 10000;
|
|
||||||
public final static Map<Integer, String> _ERROR = new HashMap<>();
|
|
||||||
static {
|
|
||||||
_ERROR.put(400, "Bad Request");
|
|
||||||
_ERROR.put(401, "Unauthorized");
|
|
||||||
_ERROR.put(403, "Forbidden");
|
|
||||||
_ERROR.put(404, "Not Found");
|
|
||||||
_ERROR.put(413, "Request Entity Too Large");
|
|
||||||
_ERROR.put(415, "Unsupported Media Type");
|
|
||||||
_ERROR.put(500, "Internal Server Error");
|
|
||||||
_ERROR.put(502, "Bad Gateway");
|
|
||||||
_ERROR.put(503, "Service Unavailable");
|
|
||||||
_ERROR.put(504, "Gateway Timeout");
|
|
||||||
_ERROR.put(504, "Gateway Timeout");
|
|
||||||
_ERROR.put(10000, "服务请求失败,请稍后再试"); // 默认错误提示
|
|
||||||
_ERROR.put(10001, "应用禁止访问,请联系管理员");
|
|
||||||
_ERROR.put(10010, "无法找到路由地址");
|
|
||||||
_ERROR.put(10011, "无法找到匹配的加解密算法");
|
|
||||||
_ERROR.put(10012, "参数传递错误");
|
|
||||||
_ERROR.put(10013, "无法匹配加解密、熔断代理模式");
|
|
||||||
_ERROR.put(10014, "反向代理执行错误");
|
|
||||||
_ERROR.put(10015, "请求url被限流");
|
|
||||||
_ERROR.put(10016, "请求url被熔断");
|
|
||||||
_ERROR.put(10017, "应用请求url被限流");
|
|
||||||
_ERROR.put(10018, "apiCode与uri不匹配");
|
|
||||||
_ERROR.put(10019, "请求不支持conetnt-type类型");
|
|
||||||
_ERROR.put(10020, "uri返回mock数据");
|
|
||||||
_ERROR.put(10021, "无法找到负载均衡路由节点");
|
|
||||||
_ERROR.put(10022, "uri模糊匹配,不能使用加解密、熔断策略.");
|
|
||||||
};
|
|
||||||
|
|
||||||
public static JsonObject returnErrorMsg(Integer errorCode) {
|
|
||||||
JsonObject json = new JsonObject();
|
|
||||||
String msg = _ERROR.get(errorCode);
|
|
||||||
if(StringUtils.isBlank(msg)) {
|
|
||||||
// default
|
|
||||||
json.put("code", DEFAULT_ERROR_CODE);
|
|
||||||
json.put("msg", _ERROR.get(DEFAULT_ERROR_CODE));
|
|
||||||
} else {
|
|
||||||
json.put("code", errorCode);
|
|
||||||
json.put("msg", msg);
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.exception;
|
||||||
|
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.exception;
|
||||||
|
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.sf.vertx.exception;
|
||||||
|
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务异常
|
||||||
|
*/
|
||||||
|
public class ServiceException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 7975954645547803572L;
|
||||||
|
private final int statusCode;
|
||||||
|
private final String payload;
|
||||||
|
|
||||||
|
public ServiceException() {
|
||||||
|
this(GatewayError.DEFAULT_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(GatewayError gatewayError, String payload) {
|
||||||
|
this(gatewayError.getCode(), payload, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceException(GatewayError gatewayError) {
|
||||||
|
this(gatewayError.getCode(), gatewayError.getReasonPhrase(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceException(int statusCode, String payload, Throwable cause) {
|
||||||
|
super("(" + statusCode + ")" + payload, cause, false, false);
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatusCode() {
|
||||||
|
return statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
import com.sf.vertx.api.pojo.MockResponse;
|
import com.sf.vertx.api.pojo.MockResponse;
|
||||||
import com.sf.vertx.constans.SacErrorCode;
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.MockException;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
|
import com.sf.vertx.utils.AppUtils;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.ext.web.handler.HttpException;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -12,16 +14,15 @@ public class ApiMockHandlerImpl implements ApiMockHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext rc) {
|
public void handle(RoutingContext rc) {
|
||||||
try {
|
try {
|
||||||
String cacheKey = AppConfigHandler.getApiCodeConfigCacheKey(rc);
|
|
||||||
// mock
|
// mock
|
||||||
MockResponse mockResponse = AppConfigHandler.mock(cacheKey, rc);
|
MockResponse mockResponse = AppUtils.mock(rc);
|
||||||
if (mockResponse != null) {
|
if (mockResponse != null) {
|
||||||
rc.fail(new MockException(mockResponse.getHttpStatus(), mockResponse.getMockResponse()));
|
rc.fail(new MockException(mockResponse.getHttpStatus(), mockResponse.getMockResponse()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("ApiMockHandlerImpl:",e);
|
||||||
rc.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE));
|
rc.fail(new ServiceException(GatewayError.DEFAULT_SERVICE_ERROR));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rc.next();
|
rc.next();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
import com.sf.vertx.constans.RedisKeyConfig;
|
import com.sf.vertx.constans.RedisKeyConfig;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
import com.sf.vertx.pojo.SacCurrentLimiting;
|
import com.sf.vertx.pojo.SacCurrentLimiting;
|
||||||
|
|
||||||
import io.github.resilience4j.core.functions.CheckedRunnable;
|
import io.github.resilience4j.core.functions.CheckedRunnable;
|
||||||
@ -9,6 +11,8 @@ import io.vertx.ext.web.RoutingContext;
|
|||||||
import io.vertx.ext.web.handler.HttpException;
|
import io.vertx.ext.web.handler.HttpException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static com.sf.vertx.constans.SACConstants.CACHE_KEY_CONNECTOR;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* 内存存储
|
* 内存存储
|
||||||
*
|
*
|
||||||
@ -20,31 +24,26 @@ public class ApiRateLimitHandlerImpl implements ApiRateLimitHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext rc) {
|
public void handle(RoutingContext rc) {
|
||||||
|
log.info("Enter ApiRateLimitHandlerImpl.handle()");
|
||||||
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
||||||
String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
||||||
|
|
||||||
SacCurrentLimiting currentLimiting = AppConfigHandler.getApiCurrentLimiting(appCode, apiCode);
|
SacCurrentLimiting currentLimiting = AppConfigHandler.getApiCurrentLimiting(appCode, apiCode);
|
||||||
|
|
||||||
if(currentLimiting != null) {
|
if(currentLimiting != null) {
|
||||||
String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + ":" + appCode + ":" + apiCode + ":" + rc.request().uri()
|
String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + CACHE_KEY_CONNECTOR + appCode + CACHE_KEY_CONNECTOR + apiCode + CACHE_KEY_CONNECTOR + rc.request().uri()
|
||||||
+ ":" + rc.request().method();
|
+ CACHE_KEY_CONNECTOR + rc.request().method();
|
||||||
RateLimiter rateLimiter = currentLimiting.getRegistry().rateLimiter(key);
|
RateLimiter rateLimiter = currentLimiting.getRegistry().rateLimiter(key);
|
||||||
CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter,
|
CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, rc::next);
|
||||||
() -> {
|
|
||||||
rc.next();
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
try {
|
try {
|
||||||
restrictedCall.run();
|
restrictedCall.run();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
//t.printStackTrace();
|
//t.printStackTrace();
|
||||||
log.info("api ratelimit:{}", key);
|
log.info("api ratelimit:{}", key);
|
||||||
rc.fail(new HttpException(10015, currentLimiting.getStrategy().getDefaultResponse()));
|
rc.fail(new ServiceException(GatewayError.REQUEST_URL_RESTRICTED_BY_FLOW, currentLimiting.getStrategy().getDefaultResponse()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc.next();
|
rc.next();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,8 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
import com.sf.vertx.constans.RedisKeyConfig;
|
import com.sf.vertx.constans.RedisKeyConfig;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
import com.sf.vertx.pojo.SacCurrentLimiting;
|
import com.sf.vertx.pojo.SacCurrentLimiting;
|
||||||
|
|
||||||
import io.github.resilience4j.core.functions.CheckedRunnable;
|
import io.github.resilience4j.core.functions.CheckedRunnable;
|
||||||
@ -20,27 +22,23 @@ public class AppRateLimitHandlerImpl implements AppRateLimitHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext rc) {
|
public void handle(RoutingContext rc) {
|
||||||
|
log.info("Enter AppRateLimitHandlerImpl.handle()");
|
||||||
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
||||||
SacCurrentLimiting currentLimiting = AppConfigHandler.getGlobalAppCurrentLimitingConfig(appCode);
|
SacCurrentLimiting currentLimiting = AppConfigHandler.getGlobalAppCurrentLimitingConfig(appCode);
|
||||||
|
|
||||||
if (currentLimiting != null) {
|
if (currentLimiting != null) {
|
||||||
String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + ":" + appCode;
|
String key = RedisKeyConfig.APP_CURRENT_LIMITING_CONFIG_KEY + ":" + appCode;
|
||||||
RateLimiter rateLimiter = currentLimiting.getRegistry().rateLimiter(key);
|
RateLimiter rateLimiter = currentLimiting.getRegistry().rateLimiter(key);
|
||||||
CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, () -> {
|
CheckedRunnable restrictedCall = RateLimiter.decorateCheckedRunnable(rateLimiter, rc::next);
|
||||||
rc.next();
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
try {
|
try {
|
||||||
restrictedCall.run();
|
restrictedCall.run();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
//t.printStackTrace();
|
//t.printStackTrace();
|
||||||
log.info("app ratelimit:{}", key);
|
log.info("app ratelimit:{}", key);
|
||||||
rc.fail(new HttpException(10015, currentLimiting.getStrategy().getDefaultResponse()));
|
rc.fail(new ServiceException(GatewayError.REQUEST_URL_RESTRICTED_BY_FLOW, currentLimiting.getStrategy().getDefaultResponse()));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc.next();
|
rc.next();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,6 @@ import java.util.List;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import com.sf.vertx.constans.SacErrorCode;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2014 Red Hat, Inc.
|
* Copyright 2014 Red Hat, Inc.
|
||||||
*
|
*
|
||||||
@ -25,6 +21,10 @@ import com.sf.vertx.constans.SacErrorCode;
|
|||||||
* You may elect to redistribute this code under either of these licenses.
|
* You may elect to redistribute this code under either of these licenses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import com.sf.vertx.api.pojo.ApiConfig;
|
||||||
|
import com.sf.vertx.api.pojo.AppConfig;
|
||||||
|
import com.sf.vertx.enums.RequestMethod;
|
||||||
|
import com.sf.vertx.utils.AppUtils;
|
||||||
import io.netty.handler.codec.DecoderException;
|
import io.netty.handler.codec.DecoderException;
|
||||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
@ -39,10 +39,11 @@ import io.vertx.core.impl.logging.Logger;
|
|||||||
import io.vertx.core.impl.logging.LoggerFactory;
|
import io.vertx.core.impl.logging.LoggerFactory;
|
||||||
import io.vertx.ext.web.FileUpload;
|
import io.vertx.ext.web.FileUpload;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.ext.web.handler.HttpException;
|
|
||||||
import io.vertx.ext.web.impl.FileUploadImpl;
|
import io.vertx.ext.web.impl.FileUploadImpl;
|
||||||
import io.vertx.ext.web.impl.RoutingContextInternal;
|
import io.vertx.ext.web.impl.RoutingContextInternal;
|
||||||
|
|
||||||
|
import static com.sf.vertx.constans.SACConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="http://tfox.org">Tim Fox</a>
|
* @author <a href="http://tfox.org">Tim Fox</a>
|
||||||
*/
|
*/
|
||||||
@ -77,94 +78,82 @@ public class BodyHandlerImpl implements BodyHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext context) {
|
public void handle(RoutingContext context) {
|
||||||
// TODO 改造了这个地方
|
// =======源码流程
|
||||||
final HttpServerRequest request = context.request();
|
final HttpServerRequest request = context.request();
|
||||||
final HttpServerResponse response = context.response();
|
final HttpServerResponse response = context.response();
|
||||||
String appCode = context.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
//
|
||||||
String apiCode = context.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
// we need to keep state since we can be called again on reroute
|
||||||
String contentType = context.request().headers().get(HttpHeaders.CONTENT_TYPE);
|
if (!((RoutingContextInternal) context).seenHandler(RoutingContextInternal.BODY_HANDLER)) {
|
||||||
boolean isLoadBody = false;
|
((RoutingContextInternal) context).visitHandler(RoutingContextInternal.BODY_HANDLER);
|
||||||
try {
|
|
||||||
isLoadBody = AppConfigHandler.isAnalysisBody(appCode, apiCode, contentType);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
context.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isLoadBody) {
|
|
||||||
// =======源码流程
|
|
||||||
// final HttpServerRequest request = context.request();
|
|
||||||
// final HttpServerResponse response = context.response();
|
|
||||||
//
|
|
||||||
// we need to keep state since we can be called again on reroute
|
|
||||||
if (!((RoutingContextInternal) context).seenHandler(RoutingContextInternal.BODY_HANDLER)) {
|
|
||||||
((RoutingContextInternal) context).visitHandler(RoutingContextInternal.BODY_HANDLER);
|
|
||||||
|
|
||||||
// Check if a request has a request body.
|
// Check if a request has a request body.
|
||||||
// A request with a body __must__ either have `transfer-encoding`
|
// A request with a body __must__ either have `transfer-encoding`
|
||||||
// or `content-length` headers set.
|
// or `content-length` headers set.
|
||||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
|
||||||
final long parsedContentLength = parseContentLengthHeader(request);
|
final long parsedContentLength = parseContentLengthHeader(request);
|
||||||
// http2 never transmits a `transfer-encoding` as frames are chunks.
|
// http2 never transmits a `transfer-encoding` as frames are chunks.
|
||||||
final boolean hasTransferEncoding = request.version() == HttpVersion.HTTP_2
|
final boolean hasTransferEncoding = request.version() == HttpVersion.HTTP_2
|
||||||
|| request.headers().contains(HttpHeaders.TRANSFER_ENCODING);
|
|| request.headers().contains(HttpHeaders.TRANSFER_ENCODING);
|
||||||
|
|
||||||
if (!hasTransferEncoding && parsedContentLength == -1) {
|
if (!hasTransferEncoding && parsedContentLength == -1) {
|
||||||
// there is no "body", so we can skip this handler
|
// there is no "body", so we can skip this handler
|
||||||
context.next();
|
context.next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// before parsing the body we can already discard a bad request just by
|
// before parsing the body we can already discard a bad request just by
|
||||||
// inspecting the content-length against
|
// inspecting the content-length against
|
||||||
// the body limit, this will reduce load, on the server by totally skipping
|
// the body limit, this will reduce load, on the server by totally skipping
|
||||||
// parsing the request body
|
// parsing the request body
|
||||||
if (bodyLimit != -1 && parsedContentLength != -1) {
|
if (bodyLimit != -1 && parsedContentLength != -1) {
|
||||||
if (parsedContentLength > bodyLimit) {
|
if (parsedContentLength > bodyLimit) {
|
||||||
context.fail(413);
|
context.fail(413);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle expectations
|
// handle expectations
|
||||||
// https://httpwg.org/specs/rfc7231.html#header.expect
|
// https://httpwg.org/specs/rfc7231.html#header.expect
|
||||||
final String expect = request.getHeader(HttpHeaders.EXPECT);
|
final String expect = request.getHeader(HttpHeaders.EXPECT);
|
||||||
if (expect != null) {
|
if (expect != null) {
|
||||||
// requirements validation
|
// requirements validation
|
||||||
if (expect.equalsIgnoreCase("100-continue")) {
|
if (expect.equalsIgnoreCase("100-continue")) {
|
||||||
// A server that receives a 100-continue expectation in an HTTP/1.0 request MUST
|
// A server that receives a 100-continue expectation in an HTTP/1.0 request MUST
|
||||||
// ignore that expectation.
|
// ignore that expectation.
|
||||||
if (request.version() != HttpVersion.HTTP_1_0) {
|
if (request.version() != HttpVersion.HTTP_1_0) {
|
||||||
// signal the client to continue
|
// signal the client to continue
|
||||||
response.writeContinue();
|
response.writeContinue();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// the server cannot meet the expectation, we only know about 100-continue
|
// the server cannot meet the expectation, we only know about 100-continue
|
||||||
context.fail(417);
|
context.fail(417);
|
||||||
return;
|
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// TODO 改造了这个地方 在真正解析body之前验证是否需要继续解析
|
||||||
|
AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(context);
|
||||||
|
ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(context);
|
||||||
|
String apiServiceType = context.get(API_SERVICE_TYPE);
|
||||||
|
if (!AppUtils.isAnalysisBody(appConfig,apiConfig,apiServiceType)){
|
||||||
context.next();
|
context.next();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 非加解密不处理
|
final BHandler handler = new BHandler(context, isPreallocateBodyBuffer ? parsedContentLength : -1);
|
||||||
context.next();
|
boolean ended = request.isEnded();
|
||||||
return;
|
if (!ended) {
|
||||||
}
|
request
|
||||||
|
// resume the request (if paused)
|
||||||
|
.handler(handler).endHandler(handler::end).resume();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// on reroute we need to re-merge the form params if that was desired
|
||||||
|
if (mergeFormAttributes && request.isExpectMultipart()) {
|
||||||
|
request.params().addAll(request.formAttributes());
|
||||||
|
}
|
||||||
|
context.next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
|
import com.sf.vertx.api.pojo.ApiConfig;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
|
|
||||||
|
import com.sf.vertx.api.pojo.AppConfig;
|
||||||
|
|
||||||
|
import com.sf.vertx.utils.AppUtils;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static com.sf.vertx.constans.SACConstants.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class OpenParameterCheckHandlerImpl implements ParameterCheckHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(RoutingContext rc) {
|
||||||
|
try {
|
||||||
|
log.info("Enter OPEN Route");
|
||||||
|
// 判断OPEN模式, header不传递参数, 走域名映射
|
||||||
|
String domain = rc.request().authority().host();
|
||||||
|
log.info("request domain:{}", domain);
|
||||||
|
AppConfig appConfig = AppConfigHandler.getAppConfigByDomain(domain);
|
||||||
|
if (appConfig == null) {
|
||||||
|
rc.fail(new ServiceException(GatewayError.APP_SERVICE_NOT_FOUND));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String apiCacheKey = appConfig.getAppCode() + CACHE_KEY_CONNECTOR + domain;
|
||||||
|
ApiConfig apiConfig = AppConfigHandler.getApicodeConfig(apiCacheKey);
|
||||||
|
if (apiConfig == null) {
|
||||||
|
rc.fail(new ServiceException(GatewayError.API_SERVICE_NOT_FOUND));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 设置应用配置、接口配置到上下文
|
||||||
|
AppUtils.setAppConfigToRoutingContext(appConfig,rc);
|
||||||
|
AppUtils.setApiConfigIntoRoutingContext(apiConfig,rc);
|
||||||
|
rc.put(API_SERVICE_TYPE,AppConfigHandler.getServiceTypeOpen(apiCacheKey));
|
||||||
|
// 将appcode和apicode设置到请求头,兼容原有逻辑
|
||||||
|
rc.request().headers().add(AppConfigHandler.getAppCodeHeaderKey(), appConfig.getAppCode());
|
||||||
|
rc.request().headers().add(AppConfigHandler.getApiCodeHeaderKey(), apiConfig.getApiCode());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("OpenParameterCheckHandlerImpl Error:",e);
|
||||||
|
rc.fail(new ServiceException(GatewayError.DEFAULT_SERVICE_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rc.next();
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,29 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
|
import com.sf.vertx.enums.GatewayServiceType;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
import io.vertx.codegen.annotations.VertxGen;
|
import io.vertx.codegen.annotations.VertxGen;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* 入口参数校验
|
* 入口参数校验
|
||||||
*
|
*
|
||||||
* @author xy
|
* @author xy
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@VertxGen
|
@VertxGen
|
||||||
public interface ParameterCheckHandler extends Handler<RoutingContext> {
|
public interface ParameterCheckHandler extends Handler<RoutingContext> {
|
||||||
|
|
||||||
static ParameterCheckHandler create() {
|
static ParameterCheckHandler create(GatewayServiceType serviceType) {
|
||||||
return new ParameterCheckHandlerImpl();
|
switch (serviceType) {
|
||||||
}
|
case SAC:
|
||||||
|
return new SACParameterCheckHandlerImpl();
|
||||||
|
case OPEN:
|
||||||
|
return new OpenParameterCheckHandlerImpl();
|
||||||
|
default:
|
||||||
|
throw new ServiceException(GatewayError.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
package com.sf.vertx.handle;
|
|
||||||
|
|
||||||
import com.sf.vertx.api.pojo.MockResponse;
|
|
||||||
import io.vertx.ext.web.RequestBody;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import com.sf.vertx.api.pojo.AppConfig;
|
|
||||||
import com.sf.vertx.constans.SacErrorCode;
|
|
||||||
|
|
||||||
import io.vertx.ext.web.RoutingContext;
|
|
||||||
import io.vertx.ext.web.handler.HttpException;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class ParameterCheckHandlerImpl implements ParameterCheckHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(RoutingContext rc) {
|
|
||||||
try {
|
|
||||||
String domain = rc.request().authority().host();
|
|
||||||
log.info("domain:{}", domain);
|
|
||||||
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
|
||||||
String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
|
||||||
String key = appCode + ":" + apiCode;
|
|
||||||
if (StringUtils.isBlank(appCode) || StringUtils.isBlank(apiCode)
|
|
||||||
|| AppConfigHandler.getAppConfig(appCode) == null
|
|
||||||
|| AppConfigHandler.getApicodeConfig(key) == null) {
|
|
||||||
// 判断OPEN模式, header不传递参数, 走域名映射
|
|
||||||
AppConfig appConfig = AppConfigHandler.getAppConfigByDomain(domain);
|
|
||||||
if(appConfig != null) {
|
|
||||||
appCode = appConfig.getAppCode();
|
|
||||||
apiCode = domain;
|
|
||||||
rc.request().headers().add(AppConfigHandler.getAppCodeHeaderKey(), appCode);
|
|
||||||
rc.request().headers().add(AppConfigHandler.getApiCodeHeaderKey(), apiCode);
|
|
||||||
key = appCode + ":" + apiCode;
|
|
||||||
} else {
|
|
||||||
rc.fail(new HttpException(10012));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(AppConfigHandler.isDisabledAppcode(apiCode)) {
|
|
||||||
rc.fail(new HttpException(10001));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通过请求模式来区分
|
|
||||||
String uri = rc.request().uri();
|
|
||||||
String httpMethod = rc.request().method().name();
|
|
||||||
if(AppConfigHandler.isServiceTypeOpen(key) && AppConfigHandler.isApicodeUri(key, uri, httpMethod) == false) {
|
|
||||||
rc.fail(new HttpException(10018));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
rc.fail(new HttpException(SacErrorCode.DEFAULT_ERROR_CODE));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
rc.next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +1,66 @@
|
|||||||
package com.sf.vertx.handle;
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
import io.vertx.core.buffer.Buffer;
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.MockException;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
|
import com.sf.vertx.utils.AppUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.sf.vertx.constans.SacErrorCode;
|
|
||||||
|
|
||||||
import io.vertx.core.http.HttpHeaders;
|
|
||||||
import io.vertx.core.json.JsonObject;
|
import io.vertx.core.json.JsonObject;
|
||||||
import io.vertx.ext.web.RoutingContext;
|
import io.vertx.ext.web.RoutingContext;
|
||||||
import io.vertx.ext.web.handler.HttpException;
|
import io.vertx.ext.web.handler.HttpException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class RestfulFailureHandlerImpl implements RestfulFailureHandler {
|
public class RestfulFailureHandlerImpl implements RestfulFailureHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(RoutingContext frc) {
|
public void handle(RoutingContext frc) {
|
||||||
int statusCode = 500;
|
int statusCode = 500;
|
||||||
JsonObject errorJson = null;
|
JsonObject errorJson;
|
||||||
Integer sc = SacErrorCode.DEFAULT_ERROR_CODE;
|
// 网关的业务码
|
||||||
|
int gatewayServiceCode = GatewayError.DEFAULT_SERVICE_ERROR.getCode();
|
||||||
try {
|
try {
|
||||||
Throwable failure = frc.failure();
|
Throwable failure = frc.failure();
|
||||||
log.info("failure:", failure);
|
log.info("failure:", failure);
|
||||||
if (failure instanceof HttpException) {
|
if (failure instanceof HttpException) {
|
||||||
HttpException httpException = (HttpException) failure;
|
HttpException httpException = (HttpException) failure;
|
||||||
sc = httpException.getStatusCode();
|
gatewayServiceCode = httpException.getStatusCode();
|
||||||
if (StringUtils.isNoneBlank(httpException.getPayload())) {
|
errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.getByCode(statusCode));
|
||||||
errorJson = new JsonObject(httpException.getPayload());
|
if (StringUtils.isNotBlank(httpException.getPayload())){
|
||||||
} else {
|
errorJson.put("msg",httpException.getPayload());
|
||||||
errorJson = SacErrorCode.returnErrorMsg(httpException.getStatusCode());
|
|
||||||
}
|
}
|
||||||
} else if (failure instanceof MockException) {
|
} else if (failure instanceof MockException) {
|
||||||
MockException httpException = (MockException) failure;
|
MockException mockException = (MockException) failure;
|
||||||
sc = httpException.getStatusCode();
|
gatewayServiceCode = mockException.getStatusCode();
|
||||||
statusCode = httpException.getStatusCode();
|
statusCode = mockException.getStatusCode();
|
||||||
if (StringUtils.isNoneBlank(httpException.getPayload())) {
|
errorJson = new JsonObject(mockException.getPayload());
|
||||||
errorJson = new JsonObject(httpException.getPayload());
|
}else if (failure instanceof ServiceException) {
|
||||||
} else {
|
ServiceException serviceException = (ServiceException) failure;
|
||||||
errorJson = SacErrorCode.returnErrorMsg(httpException.getStatusCode());
|
gatewayServiceCode = serviceException.getStatusCode();
|
||||||
|
// 业务异常,为网关业务错误,响应码设置为500,
|
||||||
|
GatewayError gatewayError = GatewayError.getByCode(serviceException.getStatusCode());
|
||||||
|
// 如果是被限流或熔断,直接返回限流或熔断响应
|
||||||
|
if (GatewayError.REQUEST_URL_RESTRICTED_BY_FLOW.equals(gatewayError)
|
||||||
|
|| GatewayError.REQUEST_URL_IS_BROKEN.equals(gatewayError)){
|
||||||
|
errorJson = new JsonObject(serviceException.getPayload());
|
||||||
|
}else {
|
||||||
|
errorJson = AppUtils.getResponseJsonByGatewayError(gatewayError);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errorJson = SacErrorCode.returnErrorMsg(SacErrorCode.DEFAULT_ERROR_CODE);
|
errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.getByCode(statusCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("RestfulFailureHandlerImpl.handle Error:",e);
|
||||||
errorJson = SacErrorCode.returnErrorMsg(SacErrorCode.DEFAULT_ERROR_CODE);
|
errorJson = AppUtils.getResponseJsonByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
frc.response().setChunked(true).setStatusCode(statusCode).putHeader("Content-Type", "application/json")
|
frc.response().setChunked(true).setStatusCode(statusCode).putHeader("Content-Type", "application/json")
|
||||||
.putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(sc))
|
.putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(gatewayServiceCode))
|
||||||
.end(errorJson.toBuffer());
|
.end(errorJson.toBuffer());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.sf.vertx.handle;
|
||||||
|
|
||||||
|
import com.sf.vertx.api.pojo.ApiConfig;
|
||||||
|
import com.sf.vertx.api.pojo.AppConfig;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.exception.ServiceException;
|
||||||
|
import com.sf.vertx.utils.AppUtils;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import static com.sf.vertx.constans.SACConstants.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class SACParameterCheckHandlerImpl implements ParameterCheckHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(RoutingContext rc) {
|
||||||
|
try {
|
||||||
|
log.info("Enter SAC Route");
|
||||||
|
// SAC规范要求Header必须要同时包含appCode和apiCode
|
||||||
|
String appCode = rc.request().headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
||||||
|
String apiCode = rc.request().headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
||||||
|
if (StringUtils.isBlank(appCode) || StringUtils.isBlank(apiCode)) {
|
||||||
|
rc.fail(new ServiceException(GatewayError.PARAMETER_TRANSFER_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AppConfig appConfig = AppConfigHandler.getAppConfig(appCode);
|
||||||
|
if (appConfig == null) {
|
||||||
|
rc.fail(new ServiceException(GatewayError.APP_SERVICE_NOT_FOUND));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String apiCacheKey = appConfig.getAppCode() + CACHE_KEY_CONNECTOR + apiCode;
|
||||||
|
ApiConfig apiConfig = AppConfigHandler.getApicodeConfig(apiCacheKey);
|
||||||
|
if (apiConfig == null) {
|
||||||
|
rc.fail(new ServiceException(GatewayError.API_SERVICE_NOT_FOUND));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 设置应用配置、接口配置到上下文
|
||||||
|
AppUtils.setAppConfigToRoutingContext(appConfig,rc);
|
||||||
|
AppUtils.setApiConfigIntoRoutingContext(apiConfig,rc);
|
||||||
|
rc.put(API_SERVICE_TYPE,AppConfigHandler.getServiceTypeOpen(apiCacheKey));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SACParameterCheckHandlerImpl Error:",e);
|
||||||
|
rc.fail(new ServiceException(GatewayError.DEFAULT_SERVICE_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rc.next();
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ public class MainSecurity {
|
|||||||
*/
|
*/
|
||||||
public static String rsaEncrypt(String content, String pubKey) {
|
public static String rsaEncrypt(String content, String pubKey) {
|
||||||
try {
|
try {
|
||||||
return RSAUtil.encrypt1(content, pubKey);
|
return RSAUtil.encrypt(content, pubKey);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.info("RSA加密失败");
|
LOGGER.info("RSA加密失败");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -27,7 +27,7 @@ public class MainSecurity {
|
|||||||
|
|
||||||
public static String rsaDecrypt(String content, String priKey) {
|
public static String rsaDecrypt(String content, String priKey) {
|
||||||
try {
|
try {
|
||||||
return RSAUtil.decrypt1(content, priKey);
|
return RSAUtil.decrypt(content, priKey);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.info("RSA解密失败");
|
LOGGER.info("RSA解密失败");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
File diff suppressed because one or more lines are too long
255
sf-vertx/src/main/java/com/sf/vertx/utils/AppUtils.java
Normal file
255
sf-vertx/src/main/java/com/sf/vertx/utils/AppUtils.java
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
package com.sf.vertx.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
|
import com.sf.vertx.api.pojo.*;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
|
import com.sf.vertx.enums.GatewayServiceType;
|
||||||
|
import com.sf.vertx.enums.MatchType;
|
||||||
|
import com.sf.vertx.enums.RequestMethod;
|
||||||
|
import com.sf.vertx.handle.AppConfigHandler;
|
||||||
|
import io.vertx.circuitbreaker.CircuitBreaker;
|
||||||
|
import io.vertx.core.http.HttpServerRequest;
|
||||||
|
import io.vertx.core.json.JsonObject;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.sf.vertx.constans.SACConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述:
|
||||||
|
*
|
||||||
|
* @author a_kun
|
||||||
|
* @date 2024/5/24 12:30
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@UtilityClass
|
||||||
|
public class AppUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将AppConfig设置到上下文中
|
||||||
|
* 配合getAppConfigFromRoutingContext(RoutingContext rc)使用
|
||||||
|
* @param appConfig
|
||||||
|
* @param rc
|
||||||
|
*/
|
||||||
|
public static void setAppConfigToRoutingContext(AppConfig appConfig, RoutingContext rc) {
|
||||||
|
rc.put(APP_CONFIG,appConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从路由上下文获取AppConfig
|
||||||
|
* @param rc
|
||||||
|
* @return AppConfig
|
||||||
|
*/
|
||||||
|
public static AppConfig getAppConfigFromRoutingContext(RoutingContext rc) {
|
||||||
|
return rc.get(APP_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将AppConfig设置到上下文中
|
||||||
|
* 配合getApiConfigFromRoutingContext(RoutingContext rc)使用
|
||||||
|
* @param apiConfig
|
||||||
|
* @param rc
|
||||||
|
*/
|
||||||
|
public static void setApiConfigIntoRoutingContext(ApiConfig apiConfig, RoutingContext rc) {
|
||||||
|
rc.put(API_CONFIG,apiConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从路由上下文获取ApiConfig
|
||||||
|
* @param rc
|
||||||
|
* @return ApiConfig
|
||||||
|
*/
|
||||||
|
public static ApiConfig getApiConfigFromRoutingContext(RoutingContext rc) {
|
||||||
|
return rc.get(API_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnableMockApi(ApiConfig apiConfig) {
|
||||||
|
if (apiConfig != null) {
|
||||||
|
return apiConfig.getMockDefaultHttpStatus() != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断API服务类型是否是SAC规范服务类型
|
||||||
|
*
|
||||||
|
* @param apiServiceType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isSACServiceType(String apiServiceType) {
|
||||||
|
return GatewayServiceType.SAC.getCode().equals(apiServiceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnableDataSecurity(AppConfig appConfig) {
|
||||||
|
return appConfig != null && appConfig.getDataSecurity() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MockResponse mock(RoutingContext rc) {
|
||||||
|
AppConfig appConfig = getAppConfigFromRoutingContext(rc);
|
||||||
|
ApiConfig apiConfig = getApiConfigFromRoutingContext(rc);
|
||||||
|
String apiServiceType = rc.get(API_SERVICE_TYPE);
|
||||||
|
if (AppUtils.isEnableMockApi(apiConfig)) {
|
||||||
|
// 如果是sac服务,query和body参数都从body中取
|
||||||
|
Integer httpStatus = apiConfig.getMockDefaultHttpStatus();
|
||||||
|
String mockResponse = apiConfig.getMockDefaultResponse();
|
||||||
|
List<MockExpectation> mockExpectations = apiConfig.getMockExpectations();
|
||||||
|
if (mockExpectations != null && !mockExpectations.isEmpty()) {
|
||||||
|
String bodyStr = rc.body().asString();
|
||||||
|
if (AppUtils.isEnableDataSecurity(appConfig)) {
|
||||||
|
bodyStr = AppConfigHandler.bodyDecrypt(bodyStr, appConfig.getAppCode());
|
||||||
|
}
|
||||||
|
JsonObject jsonBody = new JsonObject(bodyStr);
|
||||||
|
for (MockExpectation mockExpectation : mockExpectations) {
|
||||||
|
// 匹配条件需要全部匹配成功
|
||||||
|
boolean matchSuccess = true;
|
||||||
|
for (MockMatchCondition matchCondition : mockExpectation.getMatchConditions()) {
|
||||||
|
if (!matchSuccess) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MatchType matchType = MatchType.getByCode(matchCondition.getMatchType());
|
||||||
|
if (matchType == null) {
|
||||||
|
matchSuccess = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String parameterPosition = matchCondition.getParameterPosition();
|
||||||
|
String parameterKey = matchCondition.getParameterKey();
|
||||||
|
List<String> parameterValue = matchCondition.getParameterValue();
|
||||||
|
String requestParameterValue = getRequestParameterValue(AppUtils.isSACServiceType(apiServiceType), parameterPosition, parameterKey, rc.request(), jsonBody);
|
||||||
|
if (!MatchType.IS_NULL.equals(matchType) && !MatchType.NOT_NULL.equals(matchType)) {
|
||||||
|
// 需要值而没有设置值,直接匹配失败
|
||||||
|
if (CollectionUtil.isEmpty(parameterValue) || requestParameterValue == null) {
|
||||||
|
matchSuccess = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (matchType) {
|
||||||
|
case EQ:
|
||||||
|
matchSuccess = parameterValue.get(0).equals(requestParameterValue);
|
||||||
|
break;
|
||||||
|
case NOT_EQ:
|
||||||
|
matchSuccess = !parameterValue.get(0).equals(requestParameterValue);
|
||||||
|
break;
|
||||||
|
case GT:
|
||||||
|
if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) {
|
||||||
|
matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) > 0;
|
||||||
|
} else {
|
||||||
|
matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) > 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GE:
|
||||||
|
if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) {
|
||||||
|
matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) >= 0;
|
||||||
|
} else {
|
||||||
|
matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) >= 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LT:
|
||||||
|
if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) {
|
||||||
|
matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) < 0;
|
||||||
|
} else {
|
||||||
|
matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) < 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LE:
|
||||||
|
if (NumberUtil.isNumber(requestParameterValue) && NumberUtil.isNumber(parameterValue.get(0))) {
|
||||||
|
matchSuccess = new BigDecimal(requestParameterValue).compareTo(new BigDecimal(parameterValue.get(0))) <= 0;
|
||||||
|
} else {
|
||||||
|
matchSuccess = requestParameterValue.compareTo(parameterValue.get(0)) <= 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
matchSuccess = parameterValue.contains(requestParameterValue);
|
||||||
|
break;
|
||||||
|
case NOT_IN:
|
||||||
|
matchSuccess = !parameterValue.contains(requestParameterValue);
|
||||||
|
break;
|
||||||
|
case IS_NULL:
|
||||||
|
matchSuccess = requestParameterValue == null;
|
||||||
|
break;
|
||||||
|
case NOT_NULL:
|
||||||
|
matchSuccess = requestParameterValue != null;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (matchSuccess) {
|
||||||
|
httpStatus = mockExpectation.getHttpStatus();
|
||||||
|
mockResponse = mockExpectation.getMockResponse();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new MockResponse(httpStatus, mockResponse);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getRequestParameterValue(Boolean isServiceTypeSac, String parameterPosition, String parameterKey, HttpServerRequest request, JsonObject jsonBody) {
|
||||||
|
switch (parameterPosition) {
|
||||||
|
case "query":
|
||||||
|
if (isServiceTypeSac) {
|
||||||
|
return jsonBody.getString(parameterKey);
|
||||||
|
}
|
||||||
|
return request.getParam(parameterKey);
|
||||||
|
case "header":
|
||||||
|
return request.getHeader(parameterKey);
|
||||||
|
case "body":
|
||||||
|
return jsonBody.getString(parameterKey);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getResponseMsgByGatewayError(GatewayError gatewayError) {
|
||||||
|
if (gatewayError != null) {
|
||||||
|
return gatewayError.getReasonPhrase();
|
||||||
|
}
|
||||||
|
return getResponseMsgByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonObject getResponseJsonByGatewayError(GatewayError gatewayError) {
|
||||||
|
if (gatewayError != null) {
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.put("code",gatewayError.getCode());
|
||||||
|
jsonObject.put("msg",gatewayError.getReasonPhrase());
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
return getResponseJsonByGatewayError(GatewayError.DEFAULT_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAnalysisBody(AppConfig appConfig, ApiConfig apiConfig,String apiServiceType) {
|
||||||
|
// 不是Mock(是mock模式的话,存在body就解析。)
|
||||||
|
if (AppUtils.isEnableMockApi(apiConfig)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// SAC模式,实际API请求方式GET,DELETE,HEAD请求需要解析body,可能需要二次处理。(SAC模式请求方式参数统一使用body传递)
|
||||||
|
// SAC模式,如果是POST或者PUT,并且没有设置数据加密则跳过
|
||||||
|
if (AppUtils.isSACServiceType(apiServiceType)) {
|
||||||
|
RequestMethod requestMethod = RequestMethod.getByCode(apiConfig.getMethod());
|
||||||
|
if (RequestMethod.GET.equals(requestMethod)
|
||||||
|
|| RequestMethod.DELETE.equals(requestMethod)
|
||||||
|
|| RequestMethod.HEAD.equals(requestMethod)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String keyCircuitBreaker = appConfig.getAppCode() + ":" + apiConfig.getApiCode() + ":" + "CIRCUIT_BREAKER";
|
||||||
|
CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
|
||||||
|
boolean isDataSecurity = AppUtils.isEnableDataSecurity(appConfig);
|
||||||
|
// 文件上传不走加解密
|
||||||
|
return (isDataSecurity || circuitBreaker != null);
|
||||||
|
}else {
|
||||||
|
// 未启用Mock,OPEN模式都不会解析body
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -18,10 +18,13 @@ import java.util.Map;
|
|||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.sf.vertx.api.pojo.ApiConfig;
|
||||||
|
import com.sf.vertx.api.pojo.AppConfig;
|
||||||
|
import com.sf.vertx.enums.GatewayError;
|
||||||
import com.sf.vertx.enums.RequestMethod;
|
import com.sf.vertx.enums.RequestMethod;
|
||||||
|
import com.sf.vertx.utils.AppUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.sf.vertx.constans.SacErrorCode;
|
|
||||||
import com.sf.vertx.handle.AppConfigHandler;
|
import com.sf.vertx.handle.AppConfigHandler;
|
||||||
import com.sf.vertx.utils.ProxyTool;
|
import com.sf.vertx.utils.ProxyTool;
|
||||||
|
|
||||||
@ -57,6 +60,7 @@ import io.vertx.httpproxy.cache.CacheOptions;
|
|||||||
import io.vertx.httpproxy.spi.cache.Cache;
|
import io.vertx.httpproxy.spi.cache.Cache;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static com.sf.vertx.constans.SACConstants.API_SERVICE_TYPE;
|
||||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
import static org.apache.commons.lang3.StringUtils.EMPTY;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -181,7 +185,7 @@ public class ReverseProxy implements HttpProxy {
|
|||||||
* @param sc
|
* @param sc
|
||||||
*/
|
*/
|
||||||
private void end(ProxyRequest proxyRequest, int sc) {
|
private void end(ProxyRequest proxyRequest, int sc) {
|
||||||
JsonObject json = SacErrorCode.returnErrorMsg(sc);
|
JsonObject json = AppUtils.getResponseJsonByGatewayError(GatewayError.getByCode(sc));
|
||||||
proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json")
|
proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json")
|
||||||
.putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(sc))
|
.putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(sc))
|
||||||
.putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(json.size())).setBody(Body.body(json.toBuffer()))
|
.putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(json.size())).setBody(Body.body(json.toBuffer()))
|
||||||
@ -345,10 +349,7 @@ public class ReverseProxy implements HttpProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private HttpRequest<Buffer> buildCallRequestBuffer(ProxyRequest proxyRequest,String body) {
|
private HttpRequest<Buffer> buildCallRequestBuffer(ProxyRequest proxyRequest,String body,ApiConfig apiConfig) {
|
||||||
String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
|
||||||
String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
|
||||||
String key = appCode + ":" + apiCode;
|
|
||||||
SocketAddress socketAddress = ProxyTool.resolveOriginAddress(proxyRequest.proxiedRequest());
|
SocketAddress socketAddress = ProxyTool.resolveOriginAddress(proxyRequest.proxiedRequest());
|
||||||
HttpRequest<Buffer> requestBuffer;
|
HttpRequest<Buffer> requestBuffer;
|
||||||
String requestURI = proxyRequest.getURI();
|
String requestURI = proxyRequest.getURI();
|
||||||
@ -369,7 +370,7 @@ public class ReverseProxy implements HttpProxy {
|
|||||||
requestBuffer = mainWebClient.post(socketAddress.port(), socketAddress.host(), requestURI);
|
requestBuffer = mainWebClient.post(socketAddress.port(), socketAddress.host(), requestURI);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
requestBuffer.timeout(AppConfigHandler.getApicodeConfigTimeOut(key));
|
requestBuffer.timeout(apiConfig.getTimeout());
|
||||||
requestBuffer.putHeaders(proxyRequest.headers());
|
requestBuffer.putHeaders(proxyRequest.headers());
|
||||||
// 处理sac请求方式
|
// 处理sac请求方式
|
||||||
RequestMethod requestMethod = RequestMethod.getByCode(proxyRequest.getMethod().name());
|
RequestMethod requestMethod = RequestMethod.getByCode(proxyRequest.getMethod().name());
|
||||||
@ -393,14 +394,14 @@ public class ReverseProxy implements HttpProxy {
|
|||||||
// 判断<br/>
|
// 判断<br/>
|
||||||
// 1、是否配置全局加解密.<br/>
|
// 1、是否配置全局加解密.<br/>
|
||||||
// 2、apiCode 配置熔断
|
// 2、apiCode 配置熔断
|
||||||
String appCode = proxyRequest.headers().get(AppConfigHandler.getAppCodeHeaderKey());
|
AppConfig appConfig = AppUtils.getAppConfigFromRoutingContext(ctx);
|
||||||
String apiCode = proxyRequest.headers().get(AppConfigHandler.getApiCodeHeaderKey());
|
ApiConfig apiConfig = AppUtils.getApiConfigFromRoutingContext(ctx);
|
||||||
String contentType = proxyRequest.headers().get(HttpHeaders.CONTENT_TYPE);
|
String apiServiceType = ctx.get(API_SERVICE_TYPE);
|
||||||
String keyCircuitBreaker = appCode + ":" + apiCode + ":" + "CIRCUIT_BREAKER";
|
String keyCircuitBreaker = appConfig.getAppCode() + ":" + apiConfig.getApiCode() + ":" + "CIRCUIT_BREAKER";
|
||||||
CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
|
CircuitBreaker circuitBreaker = AppConfigHandler.getApiCodeCircuitBreaker(keyCircuitBreaker);
|
||||||
if (AppConfigHandler.isAnalysisBody(appCode, apiCode, contentType)) {
|
if (AppUtils.isAnalysisBody(appConfig,apiConfig,apiServiceType)) {
|
||||||
String body = AppConfigHandler.isDataSecurity(appCode) ? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appCode):ctx.body().asString();
|
String body = AppUtils.isEnableDataSecurity(appConfig) ? AppConfigHandler.bodyDecrypt(ctx.body().asString(), appConfig.getAppCode()):ctx.body().asString();
|
||||||
HttpRequest<Buffer> requestBuffer = buildCallRequestBuffer(proxyRequest,body);
|
HttpRequest<Buffer> requestBuffer = buildCallRequestBuffer(proxyRequest,body,apiConfig);
|
||||||
try {
|
try {
|
||||||
if (circuitBreaker != null) {
|
if (circuitBreaker != null) {
|
||||||
return breakerCall(circuitBreaker, proxyRequest,requestBuffer,body);
|
return breakerCall(circuitBreaker, proxyRequest,requestBuffer,body);
|
||||||
@ -441,7 +442,7 @@ public class ReverseProxy implements HttpProxy {
|
|||||||
request.setTimeout(AppConfigHandler.getApicodeConfigTimeOut(key));
|
request.setTimeout(AppConfigHandler.getApicodeConfigTimeOut(key));
|
||||||
Future<ProxyResponse> fut = proxyRequest.send(request);
|
Future<ProxyResponse> fut = proxyRequest.send(request);
|
||||||
fut.onFailure(err -> {
|
fut.onFailure(err -> {
|
||||||
JsonObject json = SacErrorCode.returnErrorMsg(502);
|
JsonObject json = AppUtils.getResponseJsonByGatewayError(GatewayError.BAD_GATEWAY);
|
||||||
proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json")
|
proxyRequest.response().release().setStatusCode(500).putHeader("content-type", "application/json")
|
||||||
.putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(502))
|
.putHeader(AppConfigHandler.sacResponseHeaderKey(), String.valueOf(502))
|
||||||
.putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(json.size())).setBody(Body.body(json.toBuffer()))
|
.putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(json.size())).setBody(Body.body(json.toBuffer()))
|
||||||
|
@ -3,7 +3,7 @@ server:
|
|||||||
vertx:
|
vertx:
|
||||||
deploymentMode: 1 # 1:单机 2:集群
|
deploymentMode: 1 # 1:单机 2:集群
|
||||||
isSSL: false # vertx https或者http启动, ssl 证书有过期时间
|
isSSL: false # vertx https或者http启动, ssl 证书有过期时间
|
||||||
rpcUri: /rpc
|
rpcUri: /rpc.sac
|
||||||
sacResponseHeaderKey: sacErrorCode
|
sacResponseHeaderKey: sacErrorCode
|
||||||
environment: dev
|
environment: dev
|
||||||
server:
|
server:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user