paramBuilder() {
- return ApiConfig.getInstance().getGatewayParamBuilder();
- }
-
/**
* 处理返回结果
*/
@@ -92,24 +91,6 @@ public class BaseGatewayConfiguration extends AbstractConfiguration {
return new GatewayModifyResponseGatewayFilter();
}
- /**
- * 读取post请求参数
- */
- @Bean
- ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory() {
- return new ReadBodyRoutePredicateFactory();
- }
-
- @Bean
- NameVersionRoutePredicateFactory paramRoutePredicateFactory() {
- return new NameVersionRoutePredicateFactory();
- }
-
- @Bean
- ValidateFilter validateFilter() {
- return new ValidateFilter();
- }
-
@Bean
ParameterFormatterFilter parameterFormatterFilter() {
return new ParameterFormatterFilter();
@@ -120,11 +101,6 @@ public class BaseGatewayConfiguration extends AbstractConfiguration {
return new LimitFilter();
}
- @Bean
- LoadBalancerClientExtFilter loadBalancerClientExtFilter() {
- return new LoadBalancerClientExtFilter();
- }
-
@Bean
GatewayRouteCache gatewayRouteCache(GatewayRouteRepository gatewayRouteRepository) {
return new GatewayRouteCache(gatewayRouteRepository);
@@ -137,47 +113,30 @@ public class BaseGatewayConfiguration extends AbstractConfiguration {
return gatewayRouteRepository;
}
+ @Bean
+ GatewayForwardChooser gatewayForwardChooser() {
+ return new GatewayForwardChooser();
+ }
+ /**
+ * 扩展默认的负载均衡选择,默认使用的是RibbonLoadBalancerClient
+ * @param clientFactory
+ * @return
+ */
@Bean
- EnvGrayFilter envGrayFilter() {
- return new EnvGrayFilter();
+ LoadBalancerClient loadBalancerClient(SpringClientFactory clientFactory) {
+ return new SopLoadBalancerClient(clientFactory);
}
/**
- * 307 Temporary Redirect(临时重定向):
- *
- * 在这种情况下,请求应该与另一个URI重复,但后续的请求应仍使用原始的URI。
- * 与302相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个POST请求来重复POST请求
- *
- * 308 Permanent Redirect (永久重定向):
- *
- * 请求和所有将来的请求应该使用另一个URI重复。
- * 307和308重复302和301的行为,但不允许HTTP方法更改。 例如,将表单提交给永久重定向的资源可能会顺利进行。
- *
- * https://www.cnblogs.com/wuguanglin/p/redirect.html
- *
+ * 扩展默认的负载均衡过滤器,默认是LoadBalancerClientFilter
+ * @param sopLoadBalancerClient SopLoadBalancerClient
+ * @param loadBalancerProperties loadBalancerProperties
* @return
*/
@Bean
- @ConditionalOnProperty(value = "sop.restful.enable", havingValue = "true")
- RouterFunction routerFunction() {
- RequestPredicate requestPredicate = RequestPredicates.all()
- .and(RequestPredicates.path(restPath + "/**"));
- return RouterFunctions.route(requestPredicate, (serverRequest) -> {
- String path = serverRequest.path();
- int index = path.indexOf(restPath);
- // 取/rest的后面部分
- String servletPath = path.substring(index + restPath.length());
- String query = serverRequest.uri().getQuery();
- String appendQuery = ParamNames.API_NAME + "=" + servletPath + "&" + ParamNames.VERSION_NAME + "=";
- if (StringUtils.isBlank(query)) {
- query = appendQuery;
- } else {
- query += '&' + appendQuery;
- }
- return ServerResponse
- .temporaryRedirect(URI.create("/?" + query))
- .build();
- });
+ LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient sopLoadBalancerClient, LoadBalancerProperties loadBalancerProperties) {
+ return new SopLoadBalancerClientFilter(sopLoadBalancerClient, loadBalancerProperties);
}
+
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java
new file mode 100644
index 00000000..1ccc64e1
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ConfigChannelController.java
@@ -0,0 +1,75 @@
+package com.gitee.sop.gatewaycommon.gateway.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.gitee.sop.gatewaycommon.bean.GatewayPushDTO;
+import com.gitee.sop.gatewaycommon.bean.NacosConfigs;
+import com.gitee.sop.gatewaycommon.bean.SpringContext;
+import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
+import com.gitee.sop.gatewaycommon.manager.ChannelMsgProcessor;
+import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
+import com.gitee.sop.gatewaycommon.manager.IPBlacklistManager;
+import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager;
+import com.gitee.sop.gatewaycommon.manager.LimitConfigManager;
+import com.gitee.sop.gatewaycommon.manager.RouteConfigManager;
+import com.gitee.sop.gatewaycommon.secret.IsvManager;
+import com.gitee.sop.gatewaycommon.util.RequestUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author tanghc
+ */
+@Slf4j
+@RestController
+public class ConfigChannelController {
+
+ private static Map> processorMap = new HashMap<>(16);
+
+ static {
+ processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_GRAY, EnvGrayManager.class);
+ processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_IP_BLACKLIST, IPBlacklistManager.class);
+ processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ISV, IsvManager.class);
+ processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ROUTE_PERMISSION, IsvRoutePermissionManager.class);
+ processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_LIMIT_CONFIG, LimitConfigManager.class);
+ processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ROUTE_CONFIG, RouteConfigManager.class);
+ }
+
+ @Value("${sop.secret}")
+ private String secret;
+
+ @PostMapping("/sop/configChannelMsg")
+ public Mono configChannel(ServerWebExchange exchange) {
+ ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange);
+ // 读取请求体中的内容
+ return serverRequest.bodyToMono(String.class)
+ .flatMap(requestJson -> {
+ String sign = exchange.getRequest().getHeaders().getFirst("sign");
+ try {
+ // 签名验证
+ RequestUtil.checkResponseBody(requestJson, sign, secret);
+ } catch (Exception e) {
+ log.error("configChannelMsg错误", e);
+ return Mono.just(e.getMessage());
+ }
+ GatewayPushDTO gatewayPushDTO = JSON.parseObject(requestJson, GatewayPushDTO.class);
+ ChannelMsgProcessor channelMsgProcessor = getChannelMsgProcessor(gatewayPushDTO);
+ channelMsgProcessor.process(gatewayPushDTO.getChannelMsg());
+ return Mono.just("ok");
+ });
+ }
+
+ private ChannelMsgProcessor getChannelMsgProcessor(GatewayPushDTO gatewayPushDTO) {
+ String key = gatewayPushDTO.getGroupId() + gatewayPushDTO.getDataId();
+ Class extends ChannelMsgProcessor> aClass = processorMap.get(key);
+ return SpringContext.getBean(aClass);
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ErrorLogController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ErrorLogController.java
new file mode 100644
index 00000000..978e533a
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/ErrorLogController.java
@@ -0,0 +1,21 @@
+package com.gitee.sop.gatewaycommon.gateway.controller;
+
+import com.gitee.sop.gatewaycommon.bean.BaseErrorLogController;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ServerWebExchange;
+
+import java.util.Map;
+
+/**
+ * @author tanghc
+ */
+@RestController
+public class ErrorLogController extends BaseErrorLogController {
+
+ @Override
+ protected ApiParam getApiParam(ServerWebExchange request) {
+ Map params = request.getRequest().getQueryParams().toSingleValueMap();
+ return ApiParam.build(params);
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/GatewayController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/GatewayController.java
new file mode 100644
index 00000000..8836ad13
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/controller/GatewayController.java
@@ -0,0 +1,42 @@
+package com.gitee.sop.gatewaycommon.gateway.controller;
+
+import com.gitee.sop.gatewaycommon.bean.ApiContext;
+import com.gitee.sop.gatewaycommon.exception.ApiException;
+import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
+import com.gitee.sop.gatewaycommon.message.ErrorEnum;
+import com.gitee.sop.gatewaycommon.result.ResultExecutor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+/**
+ * @author tanghc
+ */
+@RestController
+public class GatewayController {
+
+ /**
+ * 处理签名错误返回
+ *
+ * @param exchange exchange
+ * @return 返回最终结果
+ */
+ @RequestMapping("/sop/validateError")
+ public Mono validateError(ServerWebExchange exchange) {
+ Throwable throwable = ServerWebExchangeUtil.getThrowable(exchange);
+ // 合并微服务传递过来的结果,变成最终结果
+ ResultExecutor resultExecutor = ApiContext.getApiConfig().getGatewayResultExecutor();
+ String gatewayResult = resultExecutor.buildErrorResult(exchange, throwable);
+ return Mono.just(gatewayResult);
+ }
+
+ @RequestMapping("/sop/unknown")
+ public Mono unknown(ServerWebExchange exchange) {
+ ApiException exception = ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException();
+ ResultExecutor resultExecutor = ApiContext.getApiConfig().getGatewayResultExecutor();
+ String gatewayResult = resultExecutor.buildErrorResult(exchange, exception);
+ return Mono.just(gatewayResult);
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/EnvGrayFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/EnvGrayFilter.java
index 38c9aebe..84dbbed6 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/EnvGrayFilter.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/EnvGrayFilter.java
@@ -15,7 +15,10 @@ import reactor.core.publisher.Mono;
/**
* @author tanghc
+ * @deprecated
+ * @see com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser
*/
+@Deprecated
public class EnvGrayFilter implements GlobalFilter, Ordered {
@Autowired
@@ -27,7 +30,7 @@ public class EnvGrayFilter implements GlobalFilter, Ordered {
String nameVersion = apiParam.fetchNameVersion();
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
if (targetRoute == null) {
- return null;
+ return chain.filter(exchange);
}
String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase();
// 如果服务在灰度阶段,返回一个灰度版本号
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java
new file mode 100644
index 00000000..9af4a5e3
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java
@@ -0,0 +1,156 @@
+package com.gitee.sop.gatewaycommon.gateway.filter;
+
+import com.gitee.sop.gatewaycommon.exception.ApiException;
+import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
+import com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser;
+import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import com.gitee.sop.gatewaycommon.route.ForwardInfo;
+import com.gitee.sop.gatewaycommon.validate.Validator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.gateway.support.BodyInserterContext;
+import org.springframework.cloud.gateway.support.CachedBodyOutputMessage;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
+import org.springframework.web.reactive.function.BodyInserter;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.server.ServerRequest;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.net.URI;
+import java.util.Objects;
+
+/**
+ * 入口
+ *
+ * @author tanghc
+ */
+@Slf4j
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class IndexFilter implements WebFilter {
+
+ private static final String REST_PATH_PREFIX = "/rest";
+ private static final String SOP_PATH_PREFIX = "/sop";
+
+ @Value("${sop.gateway-index-path:/}")
+ private String indexPath;
+
+ @Autowired
+ private Validator validator;
+
+ @Autowired
+ private GatewayForwardChooser gatewayForwardChooser;
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
+ ServerHttpRequest request = exchange.getRequest();
+ String path = request.getURI().getPath();
+ // SOP路径,直接放行
+ if (path.startsWith(SOP_PATH_PREFIX)) {
+ return chain.filter(exchange);
+ }
+ // 如果是restful请求,直接转发
+ if (path.startsWith(REST_PATH_PREFIX)) {
+ String sopRestfulEnableValue = EnvironmentKeys.SOP_RESTFUL_ENABLE.getValue();
+ if (!Objects.equals("true", sopRestfulEnableValue)) {
+ log.error("尝试调用restful请求,但sop.restful.enable未开启");
+ return ServerWebExchangeUtil.forwardUnknown(exchange, chain);
+ }
+ ServerWebExchange newExchange = ServerWebExchangeUtil.getRestfulExchange(exchange, path);
+ return chain.filter(newExchange);
+ }
+ if (Objects.equals(path, indexPath)) {
+ if (request.getMethod() == HttpMethod.POST) {
+ ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange);
+ // 读取请求体中的内容
+ Mono> modifiedBody = serverRequest.bodyToMono(String.class)
+ .flatMap(body -> {
+ // 构建ApiParam
+ ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange, body);
+ // 签名验证
+ doValidate(exchange, apiParam);
+ return Mono.just(body);
+ });
+ BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, (Class) String.class);
+ HttpHeaders headers = new HttpHeaders();
+ headers.putAll(exchange.getRequest().getHeaders());
+
+ // the new content type will be computed by bodyInserter
+ // and then set in the request decorator
+ headers.remove(HttpHeaders.CONTENT_LENGTH);
+
+ CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(
+ exchange, headers);
+ return bodyInserter.insert(outputMessage, new BodyInserterContext())
+ .then(Mono.defer(() -> {
+ ForwardInfo forwardInfo = gatewayForwardChooser.getForwardInfo(exchange);
+ ServerHttpRequest decorator = decorate(exchange, headers, outputMessage);
+ ServerWebExchange newExchange = exchange.mutate().request(decorator).build();
+ ServerWebExchange forwardExchange = ServerWebExchangeUtil.getForwardExchange(newExchange, forwardInfo);
+ return chain.filter(forwardExchange);
+ }));
+
+ } else {
+ URI uri = exchange.getRequest().getURI();
+ // 原始参数
+ String originalQuery = uri.getRawQuery();
+ // 构建ApiParam
+ ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange, originalQuery);
+ // 签名验证
+ doValidate(exchange, apiParam);
+
+ ForwardInfo forwardInfo = gatewayForwardChooser.getForwardInfo(exchange);
+ ServerWebExchange forwardExchange = ServerWebExchangeUtil.getForwardExchange(exchange, forwardInfo);
+ return chain.filter(forwardExchange);
+ }
+ } else {
+ return ServerWebExchangeUtil.forwardUnknown(exchange, chain);
+ }
+ }
+
+ private void doValidate(ServerWebExchange exchange, ApiParam apiParam) {
+ try {
+ validator.validate(apiParam);
+ } catch (ApiException e) {
+ log.error("验证失败,ip:{}, params:{}, errorMsg:{}", apiParam.fetchIp(), apiParam.toJSONString(), e.getMessage());
+ ServerWebExchangeUtil.setThrowable(exchange, e);
+ }
+ }
+
+ private ServerHttpRequestDecorator decorate(
+ ServerWebExchange exchange
+ , HttpHeaders headers
+ , CachedBodyOutputMessage outputMessage
+ ) {
+ return new ServerHttpRequestDecorator(exchange.getRequest()) {
+ @Override
+ public HttpHeaders getHeaders() {
+ long contentLength = headers.getContentLength();
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.putAll(super.getHeaders());
+ if (contentLength > 0) {
+ httpHeaders.setContentLength(contentLength);
+ } else {
+ httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
+ }
+ return httpHeaders;
+ }
+
+ @Override
+ public Flux getBody() {
+ return outputMessage.getBody();
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LoadBalancerClientExtFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LoadBalancerClientExtFilter.java
deleted file mode 100644
index 8cd9ad21..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LoadBalancerClientExtFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.gitee.sop.gatewaycommon.gateway.filter;
-
-import com.gitee.sop.gatewaycommon.bean.SopConstants;
-import com.gitee.sop.gatewaycommon.util.RouteUtil;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cloud.gateway.filter.GatewayFilterChain;
-import org.springframework.cloud.gateway.filter.GlobalFilter;
-import org.springframework.cloud.gateway.route.Route;
-import org.springframework.core.Ordered;
-import org.springframework.util.StringUtils;
-import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.util.UriComponentsBuilder;
-import reactor.core.publisher.Mono;
-
-import java.net.URI;
-
-import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
-import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
-import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
-
-/**
- * 在LoadBalancerClientFilter后面处理,从Route中找到具体的path,然后插入到uri的path中
- *
- * @author tanghc
- */
-@Slf4j
-public class LoadBalancerClientExtFilter implements GlobalFilter, Ordered {
-
- @Override
- public int getOrder() {
- return LOAD_BALANCER_CLIENT_FILTER_ORDER + 1;
- }
-
- @Override
- public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
- String path = this.findPath(exchange, route);
- if (StringUtils.hasLength(path)) {
- URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(url);
- uriComponentsBuilder.path(path);
- URI requestUrl = uriComponentsBuilder.build(true).toUri();
- exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
- }
- return chain.filter(exchange);
- }
-
- protected String findPath(ServerWebExchange exchange, Route route) {
- String path = exchange.getAttribute(SopConstants.REDIRECT_PATH_KEY);
- if (path != null) {
- return path;
- }
- URI routeUri = route.getUri();
- String uriStr = routeUri.toString();
- return RouteUtil.findPath(uriStr);
- }
-
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java
new file mode 100644
index 00000000..b8e74c55
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/SopLoadBalancerClientFilter.java
@@ -0,0 +1,32 @@
+package com.gitee.sop.gatewaycommon.gateway.filter;
+
+import com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
+import org.springframework.cloud.gateway.config.LoadBalancerProperties;
+import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
+import org.springframework.web.server.ServerWebExchange;
+
+import java.net.URI;
+
+import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
+
+/**
+ * 扩展负载均衡过滤器
+ * @author tanghc
+ */
+public class SopLoadBalancerClientFilter extends LoadBalancerClientFilter {
+ public SopLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
+ super(loadBalancer, properties);
+ }
+
+ @Override
+ protected ServiceInstance choose(ServerWebExchange exchange) {
+ if (loadBalancer instanceof SopLoadBalancerClient) {
+ SopLoadBalancerClient sopLoadBalancerClient = (SopLoadBalancerClient)loadBalancer;
+ return sopLoadBalancerClient.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(), exchange);
+ } else {
+ return super.choose(exchange);
+ }
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java
deleted file mode 100644
index 72c6d582..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.gitee.sop.gatewaycommon.gateway.filter;
-
-import com.gitee.sop.gatewaycommon.exception.ApiException;
-import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
-import com.gitee.sop.gatewaycommon.param.ApiParam;
-import com.gitee.sop.gatewaycommon.param.ParamBuilder;
-import com.gitee.sop.gatewaycommon.validate.Validator;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.gateway.filter.GatewayFilterChain;
-import org.springframework.cloud.gateway.filter.GlobalFilter;
-import org.springframework.core.Ordered;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-/**
- * @author tanghc
- */
-@Slf4j
-public class ValidateFilter implements GlobalFilter, Ordered {
-
- @Autowired
- private ParamBuilder paramBuilder;
-
- @Autowired
- private Validator validator;
-
- @Override
- public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- // 解析参数
- ApiParam param = paramBuilder.build(exchange);
- ServerWebExchangeUtil.setApiParam(exchange, param);
- // 验证操作,这里有负责验证签名参数
- try {
- validator.validate(param);
- } catch (ApiException e) {
- log.error("验证失败,params:{}", param.toJSONString(), e);
- throw e;
- }
- return chain.filter(exchange);
- }
-
- @Override
- public int getOrder() {
- // 最优先执行
- return Orders.VALIDATE_FILTER_ORDER;
- }
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/handler/GatewayExceptionHandler.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/handler/GatewayExceptionHandler.java
index 7d19b212..0f623358 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/handler/GatewayExceptionHandler.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/handler/GatewayExceptionHandler.java
@@ -2,15 +2,15 @@ package com.gitee.sop.gatewaycommon.gateway.handler;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
-import com.gitee.sop.gatewaycommon.gateway.result.GatewayResult;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.result.ResultExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
-import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RequestPredicates;
@@ -33,10 +33,26 @@ public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
+
+ /**
+ * MessageReader
+ */
+ private List> messageReaders = Collections.emptyList();
+
+ /**
+ * MessageWriter
+ */
+ private List> messageWriters = Collections.emptyList();
+
+ /**
+ * ViewResolvers
+ */
+ private List viewResolvers = Collections.emptyList();
+
@Override
public Mono handle(ServerWebExchange exchange, Throwable ex) {
- ResultExecutor resultExecutor = ApiContext.getApiConfig().getGatewayResultExecutor();
- GatewayResult errorResult = resultExecutor.buildErrorResult(exchange, ex);
+ ResultExecutor resultExecutor = ApiContext.getApiConfig().getGatewayResultExecutor();
+ String errorResult = resultExecutor.buildErrorResult(exchange, ex);
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange);
// 错误记录
log.error("gateway网关报错,params:{}, errorMsg:{}", apiParam, ex.getMessage(), ex);
@@ -52,21 +68,6 @@ public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
}
- /**
- * MessageReader
- */
- private List> messageReaders = Collections.emptyList();
-
- /**
- * MessageWriter
- */
- private List> messageWriters = Collections.emptyList();
-
- /**
- * ViewResolvers
- */
- private List viewResolvers = Collections.emptyList();
-
/**
* 参考AbstractErrorWebExceptionHandler
*
@@ -103,11 +104,11 @@ public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
* @param result 返回结果
* @return 返回mono
*/
- protected Mono renderErrorResponse(GatewayResult result) {
+ protected Mono renderErrorResponse(String result) {
return ServerResponse
- .status(result.getHttpStatus())
- .contentType(result.getContentType())
- .body(BodyInserters.fromObject(result.getBody()));
+ .status(HttpStatus.OK)
+ .contentType(MediaType.APPLICATION_JSON_UTF8)
+ .body(BodyInserters.fromObject(result));
}
/**
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java
new file mode 100644
index 00000000..8a6f8886
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/GatewayLoadBalanceServerChooser.java
@@ -0,0 +1,29 @@
+package com.gitee.sop.gatewaycommon.gateway.loadbalancer;
+
+import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
+import com.gitee.sop.gatewaycommon.loadbalancer.LoadBalanceServerChooser;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+import org.springframework.web.server.ServerWebExchange;
+
+/**
+ * @author tanghc
+ */
+public class GatewayLoadBalanceServerChooser extends LoadBalanceServerChooser {
+
+ public GatewayLoadBalanceServerChooser(SpringClientFactory clientFactory) {
+ this.setClientFactory(clientFactory);
+ }
+
+ @Override
+ public String getHost(ServerWebExchange exchange) {
+ return exchange.getRequest().getURI().getHost();
+ }
+
+ @Override
+ public ApiParam getApiParam(ServerWebExchange exchange) {
+ return ServerWebExchangeUtil.getApiParam(exchange);
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java
new file mode 100644
index 00000000..565fa79a
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/NacosServerIntrospector.java
@@ -0,0 +1,23 @@
+package com.gitee.sop.gatewaycommon.gateway.loadbalancer;
+
+import com.netflix.loadbalancer.Server;
+import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
+import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
+
+import java.util.Map;
+
+/**
+ * @author tanghc
+ */
+public class NacosServerIntrospector extends DefaultServerIntrospector {
+
+ @Override
+ public Map getMetadata(Server server) {
+ if (server instanceof NacosServer) {
+ NacosServer discoveryServer = (NacosServer)server;
+ return discoveryServer.getInstance().getMetadata();
+ } else {
+ return super.getMetadata(server);
+ }
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java
new file mode 100644
index 00000000..9f38866b
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/loadbalancer/SopLoadBalancerClient.java
@@ -0,0 +1,107 @@
+package com.gitee.sop.gatewaycommon.gateway.loadbalancer;
+
+import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
+import com.gitee.sop.gatewaycommon.loadbalancer.ServerChooserContext;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.Server;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
+import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
+import org.springframework.cloud.netflix.ribbon.RibbonUtils;
+import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+import org.springframework.web.server.ServerWebExchange;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 重写负载均衡处理。
+ * 默认使用的是RibbonLoadBalancerClient类,详见org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration#loadBalancerClient()
+ *
+ * @author tanghc
+ */
+public class SopLoadBalancerClient extends RibbonLoadBalancerClient implements ServerChooserContext {
+
+ private final SpringClientFactory clientFactory;
+ private GatewayLoadBalanceServerChooser loadBalanceServerChooser;
+
+ public SopLoadBalancerClient(SpringClientFactory clientFactory) {
+ super(clientFactory);
+ this.clientFactory = clientFactory;
+ this.loadBalanceServerChooser = new GatewayLoadBalanceServerChooser(clientFactory);
+ }
+
+ /**
+ * New: Select a server using a 'key'.
+ */
+ @Override
+ public ServiceInstance choose(String serviceId, Object hint) {
+ return loadBalanceServerChooser.choose(
+ serviceId
+ , (ServerWebExchange) hint
+ , this.getLoadBalancer(serviceId)
+ , () -> super.choose(serviceId, hint)
+ , (servers) -> getRibbonServer(serviceId, servers)
+ );
+ }
+
+ @Override
+ public ApiParam getApiParam(ServerWebExchange exchange) {
+ return ServerWebExchangeUtil.getApiParam(exchange);
+ }
+
+ @Override
+ public String getHost(ServerWebExchange exchange) {
+ return exchange.getRequest().getURI().getHost();
+ }
+
+ private RibbonServer getRibbonServer(String serviceId, List servers) {
+ Server server = this.chooseRandomServer(servers);
+ if (server == null) {
+ return null;
+ }
+ return new RibbonServer(
+ serviceId
+ , server
+ , isSecure(server, serviceId)
+ , serverIntrospector(serviceId).getMetadata(server)
+ );
+ }
+
+ /**
+ * 随机选取一台实例
+ *
+ * @param servers 服务列表
+ * @return 返回实例,没有返回null
+ */
+ private Server chooseRandomServer(List servers) {
+ if (servers.isEmpty()) {
+ return null;
+ }
+ int serverCount = servers.size();
+ // 随机选取一台实例
+ int index = chooseRandomInt(serverCount);
+ return servers.get(index);
+ }
+
+ private int chooseRandomInt(int serverCount) {
+ return ThreadLocalRandom.current().nextInt(serverCount);
+ }
+
+ private ServerIntrospector serverIntrospector(String serviceId) {
+ ServerIntrospector serverIntrospector = this.clientFactory.getInstance(serviceId,
+ ServerIntrospector.class);
+ if (serverIntrospector == null) {
+ serverIntrospector = new DefaultServerIntrospector();
+ }
+ return serverIntrospector;
+ }
+
+ private boolean isSecure(Server server, String serviceId) {
+ IClientConfig config = this.clientFactory.getClientConfig(serviceId);
+ ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
+ return RibbonUtils.isSecure(config, serverIntrospector, server);
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java
deleted file mode 100644
index a1054f8d..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.gitee.sop.gatewaycommon.gateway.param;
-
-import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
-import com.gitee.sop.gatewaycommon.param.ApiParam;
-import com.gitee.sop.gatewaycommon.param.BaseParamBuilder;
-import org.springframework.web.server.ServerWebExchange;
-
-/**
- * @author tanghc
- */
-public class GatewayParamBuilder extends BaseParamBuilder {
-
- @Override
- public ApiParam buildRequestParams(ServerWebExchange exchange) {
- return ServerWebExchangeUtil.getRequestParams(exchange);
- }
-
- @Override
- public String getIP(ServerWebExchange ctx) {
- return ctx.getRequest().getRemoteAddress().getAddress().getHostAddress();
- }
-
- @Override
- public void setVersionInHeader(ServerWebExchange ctx, String headerName, String version) {
- ctx.getRequest().getHeaders().add(headerName, version);
- }
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/result/GatewayResultExecutor.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/result/GatewayResultExecutor.java
index 55f57a92..3c69cdda 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/result/GatewayResultExecutor.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/result/GatewayResultExecutor.java
@@ -4,12 +4,14 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.exception.ApiException;
+import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
import com.gitee.sop.gatewaycommon.message.Error;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.result.BaseExecutorAdapter;
+import com.gitee.sop.gatewaycommon.result.ResultExecutorForGateway;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
@@ -21,7 +23,8 @@ import java.util.Map;
* @author tanghc
*/
@Slf4j
-public class GatewayResultExecutor extends BaseExecutorAdapter {
+public class GatewayResultExecutor extends BaseExecutorAdapter
+ implements ResultExecutorForGateway {
@Override
public int getResponseStatus(ServerWebExchange exchange) {
@@ -46,12 +49,12 @@ public class GatewayResultExecutor extends BaseExecutorAdapter getApiParam(ServerWebExchange exchange) {
- return exchange.getAttribute(SopConstants.CACHE_REQUEST_BODY_FOR_MAP);
+ public ApiParam getApiParam(ServerWebExchange exchange) {
+ return ServerWebExchangeUtil.getApiParam(exchange);
}
@Override
- public GatewayResult buildErrorResult(ServerWebExchange exchange, Throwable ex) {
+ public String buildErrorResult(ServerWebExchange exchange, Throwable ex) {
Error error;
if (ex instanceof ApiException) {
ApiException apiException = (ApiException) ex;
@@ -59,11 +62,8 @@ public class GatewayResultExecutor extends BaseExecutorAdapter {
+
+ private static final String VALIDATE_ERROR_PATH = "/sop/validateError";
+
+ @Override
+ public ApiParam getApiParam(ServerWebExchange exchange) {
+ return ServerWebExchangeUtil.getApiParam(exchange);
+ }
+
+ @Override
+ public ForwardInfo getForwardInfo(ServerWebExchange exchange) {
+ // 如果有异常,直接跳转到异常处理
+ if (ServerWebExchangeUtil.getThrowable(exchange) != null) {
+ return new ForwardInfo(VALIDATE_ERROR_PATH, "");
+ }
+ return super.getForwardInfo(exchange);
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteCache.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteCache.java
index dfb8e464..3e47b41c 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteCache.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteCache.java
@@ -6,11 +6,8 @@ import com.gitee.sop.gatewaycommon.manager.BaseRouteCache;
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.gateway.filter.FilterDefinition;
-import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import java.net.URI;
-import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
@@ -32,7 +29,7 @@ public class GatewayRouteCache extends BaseRouteCache {
path = path.replace('{', '?');
path = path.replace('}', '?');
}
- targetRoute.setUri(URI.create(routeDefinition.getUri() + "#" + path));
+ targetRoute.setUri(URI.create(routeDefinition.getUri() + "/" + path));
targetRoute.setOrder(routeDefinition.getOrder());
// 添加过滤器
List filterDefinitionList = routeDefinition.getFilters()
@@ -43,40 +40,7 @@ public class GatewayRouteCache extends BaseRouteCache {
return filterDefinition;
})
.collect(Collectors.toList());
-
-
- LinkedList predicateDefinitionList = routeDefinition.getPredicates()
- .stream()
- .map(predicate -> {
- PredicateDefinition predicateDefinition = new PredicateDefinition();
- BeanUtils.copyProperties(predicate, predicateDefinition);
- return predicateDefinition;
- })
- .collect(Collectors.toCollection(LinkedList::new));
- // 下面两个自定义的断言添加到顶部,注意:ReadBody需要放在最前面
- // 对应断言:
- // NameVersion -> com.gitee.sop.gatewaycommon.gateway.route.NameVersionRoutePredicateFactory
- // ReadBody -> com.gitee.sop.gatewaycommon.gateway.route.ReadBodyRoutePredicateFactory
- predicateDefinitionList.addFirst(new PredicateDefinition("NameVersion=" + routeDefinition.getId()));
- predicateDefinitionList.addFirst(new PredicateDefinition("ReadBody="));
-
- targetRoute.setFilters(filterDefinitionList);
- targetRoute.setPredicates(predicateDefinitionList);
return new GatewayTargetRoute(serviceRouteInfo, routeDefinition, targetRoute);
}
- @Override
- protected List getExtRouteDefinitionList(ServiceRouteInfo serviceRouteInfo) {
- // 在第一个位置放一个没用的路由,SpringCloudGateway会从第二个路由开始找,原因不详
- RouteDefinition routeDefinition = new RouteDefinition();
- String name = "_first_route_";
- String version = String.valueOf(System.currentTimeMillis());
- routeDefinition.setId(name + version);
- routeDefinition.setName(name);
- routeDefinition.setVersion(version);
- routeDefinition.setUri("lb://" + serviceRouteInfo.getServiceId());
- routeDefinition.setOrder(Integer.MIN_VALUE);
-
- return Collections.singletonList(routeDefinition);
- }
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteRepository.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteRepository.java
index 2a54578c..fa8c0f54 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteRepository.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteRepository.java
@@ -1,15 +1,19 @@
package com.gitee.sop.gatewaycommon.gateway.route;
+import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
-import com.gitee.sop.gatewaycommon.bean.TargetRoute;
import com.gitee.sop.gatewaycommon.manager.RouteRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
-import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
+import org.springframework.cloud.gateway.route.Route;
+import org.springframework.cloud.gateway.route.RouteLocator;
+import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
+import org.springframework.context.ApplicationContext;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -25,28 +29,37 @@ import static java.util.Collections.synchronizedMap;
* @author tanghc
*/
@Slf4j
-public class GatewayRouteRepository implements RouteDefinitionRepository, RouteRepository {
+public class GatewayRouteRepository implements RouteRepository, RouteLocator {
private PathMatcher pathMatcher = new AntPathMatcher();
private final Map routes = synchronizedMap(new LinkedHashMap<>());
- @Override
- public Flux getRouteDefinitions() {
- List list = routes.values().parallelStream()
- .map(TargetRoute::getTargetRouteDefinition)
- .collect(Collectors.toList());
- return Flux.fromIterable(list);
- }
+ @Autowired
+ private RouteLocatorBuilder routeLocatorBuilder;
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ private RouteLocator routeLocator;
@Override
- public Mono save(Mono route) {
- return null;
+ public Flux getRoutes() {
+ return routeLocator.getRoutes();
}
- @Override
- public Mono delete(Mono routeId) {
- return null;
+ public void refresh() {
+ RouteLocatorBuilder.Builder builder = routeLocatorBuilder.routes();
+ List routeDefinitionList = this.routes.values()
+ .stream()
+ .map(AbstractTargetRoute::getRouteDefinition)
+ .collect(Collectors.toList());
+ routeDefinitionList.forEach(routeDefinition -> builder.route(routeDefinition.getId(),
+ r -> r.path(routeDefinition.getPath())
+ .uri(routeDefinition.getUri())));
+ this.routeLocator = builder.build();
+ // 触发
+ applicationContext.publishEvent(new RefreshRoutesEvent(new Object()));
}
/**
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java
deleted file mode 100644
index a3a61203..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.gitee.sop.gatewaycommon.gateway.route;
-
-import com.gitee.sop.gatewaycommon.bean.SopConstants;
-import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
-import com.gitee.sop.gatewaycommon.param.ParamNames;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
-import org.springframework.util.AntPathMatcher;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.PathMatcher;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.server.ServerWebExchange;
-
-import javax.validation.constraints.NotEmpty;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Predicate;
-
-/**
- * 此断言决定执行哪个路由
- *
- * 使用地方:
- * @see com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache
- *
- * @author tanghc
- */
-@Slf4j
-public class NameVersionRoutePredicateFactory extends AbstractRoutePredicateFactory {
-
- private static final String PARAM_KEY = "param";
- private static final String REGEXP_KEY = "regexp";
-
- private PathMatcher pathMatcher = new AntPathMatcher();
-
- public NameVersionRoutePredicateFactory() {
- super(Config.class);
- }
-
- @Override
- public List shortcutFieldOrder() {
- return Arrays.asList(PARAM_KEY, REGEXP_KEY);
- }
-
- /**
- * config.param为nameVersion,即路由id
- *
- * @param config
- * @return 返回断言
- */
- @Override
- public Predicate apply(Config config) {
-
- return exchange -> {
- Map params = ServerWebExchangeUtil.getRequestParams(exchange);
- if (CollectionUtils.isEmpty(params)) {
- return false;
- }
- String nameVersion = config.param;
- Object name = params.get(ParamNames.API_NAME);
- Object version = params.get(ParamNames.VERSION_NAME);
- if (name == null || version == null) {
- return false;
- }
- String key = name.toString() + version.toString();
- // 如果是通配符
- if (nameVersion.contains("{")) {
- boolean match = pathMatcher.match(nameVersion, key);
- if (match) {
- Map attributes = exchange.getAttributes();
- attributes.put(SopConstants.REDIRECT_PATH_KEY, key);
- }
- return match;
- } else {
- return key.equals(nameVersion);
- }
- };
- }
-
- @Validated
- public static class Config {
- @NotEmpty
- private String param;
-
- private String regexp;
-
- public String getParam() {
- return param;
- }
-
- public Config setParam(String param) {
- this.param = param;
- return this;
- }
-
- public String getRegexp() {
- return regexp;
- }
-
- public Config setRegexp(String regexp) {
- this.regexp = regexp;
- return this;
- }
- }
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/ReadBodyRoutePredicateFactory.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/ReadBodyRoutePredicateFactory.java
deleted file mode 100644
index d8f48b1c..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/ReadBodyRoutePredicateFactory.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package com.gitee.sop.gatewaycommon.gateway.route;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.cloud.gateway.handler.AsyncPredicate;
-import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
-import org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory;
-import org.springframework.core.io.buffer.DataBuffer;
-import org.springframework.core.io.buffer.DataBufferUtils;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.codec.HttpMessageReader;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.reactive.function.server.HandlerStrategies;
-import org.springframework.web.reactive.function.server.ServerRequest;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.function.Predicate;
-
-import static org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter.CACHED_REQUEST_BODY_KEY;
-
-/**
- * 获取请求参数插件,兼容get,post,使用方式:
- * @Bean
- * ReadBodyRoutePredicateFactory readBodyRoutePredicateFactory() {
- * return new ReadBodyRoutePredicateFactory();
- * }
- *
- * @see org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory
- * 详见:https://blog.51cto.com/thinklili/2329184
- *
- * 使用地方:
- * @see com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache
- *
- * @author tanghc
- */
-public class ReadBodyRoutePredicateFactory extends AbstractRoutePredicateFactory {
-
- protected static final Log LOGGER = LogFactory.getLog(ReadBodyPredicateFactory.class);
-
- private static final String TEST_ATTRIBUTE = "read_body_predicate_test_attribute";
- private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
- private static final List> HTTP_MESSAGE_READERS = HandlerStrategies.withDefaults().messageReaders();
-
-
- public ReadBodyRoutePredicateFactory() {
- super(ReadBodyRoutePredicateFactory.Config.class);
- }
-
- @Override
- public AsyncPredicate applyAsync(Config config) {
- return exchange -> {
- HttpMethod method = exchange.getRequest().getMethod();
- if (method == HttpMethod.POST) {
- return this.applyForPost(exchange, config);
- } else {
- return this.applyForGet(exchange, config);
- }
- };
- }
-
- /**
- * 获取post表单参数
- * @param exchange
- * @param config
- * @return
- */
- protected Mono applyForPost(ServerWebExchange exchange, Config config) {
- Class inClass = config.getInClass();
-
- Object cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
- // We can only read the body from the request once, once that happens if we try to read the body again an
- // exception will be thrown. The below if/else caches the body object as a request attribute in the ServerWebExchange
- // so if this filter is run more than once (due to more than one route using it) we do not try to read the
- // request body multiple times
- if (cachedBody != null) {
- try {
- boolean test = config.getPredicate().test(cachedBody);
- exchange.getAttributes().put(TEST_ATTRIBUTE, test);
- return Mono.just(test);
- } catch (ClassCastException e) {
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Predicate test failed because class in predicate does not canVisit the cached body object",
- e);
- }
- }
- return Mono.just(false);
- } else {
- //Join all the DataBuffers so we have a single DataBuffer for the body
- return DataBufferUtils.join(exchange.getRequest().getBody())
- .flatMap(dataBuffer -> {
- //Update the retain counts so we can read the body twice, once to parse into an object
- //that we can test the predicate against and a second time when the HTTP client sends
- //the request downstream
- //Note: if we end up reading the body twice we will run into a problem, but as of right
- //now there is no good use case for doing this
- DataBufferUtils.retain(dataBuffer);
- //Make a slice for each read so each read has its own read/write indexes
- Flux cachedFlux = Flux.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
-
- ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
- @Override
- public Flux getBody() {
- return cachedFlux;
- }
- };
- return ServerRequest.create(exchange.mutate().request(mutatedRequest).build(), HTTP_MESSAGE_READERS)
- .bodyToMono(inClass)
- .doOnNext(objectValue -> {
- exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue);
- exchange.getAttributes().put(CACHED_REQUEST_BODY_KEY, cachedFlux);
- })
- .map(objectValue -> config.getPredicate().test(objectValue));
- });
-
- }
- }
-
- /**
- * 获取GET请求参数
- * @param exchange
- * @param config
- * @return
- */
- protected Mono applyForGet(ServerWebExchange exchange, Config config) {
- // 处理get请求
- MultiValueMap queryParams = exchange.getRequest().getQueryParams();
- String objectValue = null;
- if (queryParams != null && queryParams.size() > 0) {
- List params = new ArrayList<>(queryParams.size());
- for (Map.Entry> entry : queryParams.entrySet()) {
- params.add(entry.getKey() + "=" + entry.getValue().get(0));
- }
- objectValue = StringUtils.join(params.toArray());
- exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue);
- }
- return Mono.just(config.getPredicate().test(objectValue));
- }
-
- @Override
- public Config newConfig() {
- Config config = super.newConfig();
- config.setInClass(String.class);
- config.setPredicate(Objects::nonNull);
- return config;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Predicate apply(Config config) {
- throw new UnsupportedOperationException(
- "ReadBodyPredicateFactory is only async.");
- }
-
- public static class Config {
- private Class inClass;
- private Predicate predicate;
- private Map hints;
-
- public Class getInClass() {
- return inClass;
- }
-
- public Config setInClass(Class inClass) {
- this.inClass = inClass;
- return this;
- }
-
- public Predicate getPredicate() {
- return predicate;
- }
-
- public Config setPredicate(Class inClass, Predicate predicate) {
- setInClass(inClass);
- this.predicate = predicate;
- return this;
- }
-
- public Config setPredicate(Predicate predicate) {
- this.predicate = predicate;
- return this;
- }
-
- public Map getHints() {
- return hints;
- }
-
- public Config setHints(Map hints) {
- this.hints = hints;
- return this;
- }
- }
-
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java
deleted file mode 100644
index a3e7ddea..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EnvironmentServerChooser.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.gitee.sop.gatewaycommon.loadbalancer;
-
-import com.gitee.sop.gatewaycommon.bean.SpringContext;
-import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser;
-import com.netflix.loadbalancer.Server;
-import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
-import org.springframework.core.env.Environment;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.Map;
-
-/**
- * 预发布、灰度环境选择,参考自:https://segmentfault.com/a/1190000017412946
- *
- * @author tanghc
- */
-public class EnvironmentServerChooser extends BaseServerChooser {
-
- private static final String MEDATA_KEY_ENV = "env";
- private static final String ENV_PRE_VALUE = "pre";
- private static final String ENV_GRAY_VALUE = "gray";
-
- /**
- * 预发布机器域名
- */
- private static final String PRE_DOMAIN = "localhost";
-
- @Override
- protected boolean isPreServer(Server server) {
- String env = getEnvValue(server);
- return ENV_PRE_VALUE.equals(env);
- }
-
- @Override
- protected boolean isGrayServer(Server server) {
- String env = getEnvValue(server);
- return ENV_GRAY_VALUE.equals(env);
- }
-
- private String getEnvValue(Server server) {
- // eureka存储的metadata
- Map metadata = getMetada(server);
- return metadata.get(MEDATA_KEY_ENV);
- }
-
- protected Map getMetada(Server server) {
- return ((NacosServer) server).getMetadata();
- }
-
-
- /**
- * 通过判断hostname来确定是否是预发布请求,可修改此方法实现自己想要的
- *
- * @param request request
- * @return 返回true:可以进入到预发环境
- */
- @Override
- protected boolean canVisitPre(Server server, HttpServletRequest request) {
- String serverName = request.getServerName();
- String domain = SpringContext.getBean(Environment.class).getProperty("pre.domain", PRE_DOMAIN);
- return domain.equals(serverName);
- }
-
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java
deleted file mode 100644
index f67ba85b..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/EurekaEnvironmentServerChooser.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.gitee.sop.gatewaycommon.loadbalancer;
-
-import com.netflix.loadbalancer.Server;
-import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
-
-import java.util.Map;
-
-/**
- * @author tanghc
- */
-public class EurekaEnvironmentServerChooser extends EnvironmentServerChooser {
- @Override
- protected Map getMetada(Server server) {
- return ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();
- }
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java
new file mode 100644
index 00000000..77f6c009
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceConfig.java
@@ -0,0 +1,8 @@
+package com.gitee.sop.gatewaycommon.loadbalancer;
+
+/**
+ * @author tanghc
+ */
+public class LoadBalanceConfig {
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java
new file mode 100644
index 00000000..11dba443
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/LoadBalanceServerChooser.java
@@ -0,0 +1,128 @@
+package com.gitee.sop.gatewaycommon.loadbalancer;
+
+import com.gitee.sop.gatewaycommon.bean.SopConstants;
+import com.gitee.sop.gatewaycommon.bean.SpringContext;
+import com.netflix.loadbalancer.ILoadBalancer;
+import com.netflix.loadbalancer.Server;
+import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
+import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * 预发布、灰度发布服务器选择
+ *
+ * @author tanghc
+ */
+public abstract class LoadBalanceServerChooser implements ServerChooserContext {
+
+ private SpringClientFactory clientFactory;
+
+ /**
+ * 选择服务器
+ *
+ * @param serviceId serviceId,仅gateway网关有作用
+ * @param exchange 请求上下文
+ * @param loadBalancer loadBalancer
+ * @param superChooser 父类默认的选择
+ * @param serverChooserFunction 执行选择操作
+ * @return 返回服务器实例,没有选到则返回null
+ */
+ public R choose(
+ String serviceId
+ , T exchange
+ , ILoadBalancer loadBalancer
+ , Supplier superChooser
+ , Function, R> serverChooserFunction) {
+ // 获取所有服务实例
+ List servers = loadBalancer.getReachableServers();
+
+ // 存放预发服务器
+ List preServers = new ArrayList<>(4);
+ // 存放灰度发布服务器
+ List grayServers = new ArrayList<>(4);
+ // 存放非预发服务器
+ List notPreServers = new ArrayList<>(4);
+
+ for (Server server : servers) {
+ // 获取实例metadata
+ Map metadata = getMetadata(serviceId, server);
+ // 是否开启了预发模式
+ if (this.isPreServer(metadata)) {
+ preServers.add(server);
+ } else if (this.isGrayServer(metadata)) {
+ grayServers.add(server);
+ } else {
+ notPreServers.add(server);
+ }
+ }
+ notPreServers.addAll(grayServers);
+ // 如果没有开启预发布服务和灰度发布,直接用默认的方式
+ if (preServers.isEmpty() && grayServers.isEmpty()) {
+ return superChooser.get();
+ }
+ // 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器
+ if (this.isRequestFromPreDomain(exchange)) {
+ return serverChooserFunction.apply(preServers);
+ }
+ // 如果是灰度请求,则认为是灰度用户,选出灰度服务器
+ if (this.isRequestGrayServer(exchange)) {
+ return serverChooserFunction.apply(grayServers);
+ }
+
+ // 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器
+ // 注意:这里允许走灰度服务器,如果不允许走,注释notPreServers.addAll(grayServers);这行
+ return serverChooserFunction.apply(notPreServers);
+ }
+
+ protected Map getMetadata(String serviceId, Server server) {
+ return serverIntrospector(serviceId).getMetadata(server);
+ }
+
+ protected SpringClientFactory getSpringClientFactory() {
+ if (clientFactory == null) {
+ clientFactory = SpringContext.getBean(SpringClientFactory.class);
+ }
+ return clientFactory;
+ }
+
+ public void setClientFactory(SpringClientFactory clientFactory) {
+ this.clientFactory = clientFactory;
+ }
+
+ private ServerIntrospector serverIntrospector(String serviceId) {
+ ServerIntrospector serverIntrospector = getSpringClientFactory().getInstance(serviceId,
+ ServerIntrospector.class);
+ if (serverIntrospector == null) {
+ serverIntrospector = new DefaultServerIntrospector();
+ }
+ return serverIntrospector;
+ }
+
+ /**
+ * 是否是预发布服务器
+ *
+ * @param metadata metadata
+ * @return true:是
+ */
+ private boolean isPreServer(Map metadata) {
+ return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_PRE_VALUE);
+ }
+
+ /**
+ * 是否是灰度发布服务器
+ *
+ * @param metadata metadata
+ * @return true:是
+ */
+ private boolean isGrayServer(Map metadata) {
+ return Objects.equals(metadata.get(SopConstants.METADATA_ENV_KEY), SopConstants.METADATA_ENV_GRAY_VALUE);
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java
new file mode 100644
index 00000000..8b38406b
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/ServerChooserContext.java
@@ -0,0 +1,35 @@
+package com.gitee.sop.gatewaycommon.loadbalancer;
+
+import com.gitee.sop.gatewaycommon.bean.ApiParamAware;
+import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import org.apache.commons.lang.ArrayUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author tanghc
+ */
+public interface ServerChooserContext extends ApiParamAware {
+
+ /**
+ * 通过判断hostname来确定是否是预发布请求
+ *
+ * @param t t
+ * @return 返回true:可以进入到预发环境
+ */
+ default boolean isRequestFromPreDomain(T t) {
+ String domain = EnvironmentKeys.PRE_DOMAIN.getValue();
+ if (StringUtils.isEmpty(domain)) {
+ return false;
+ }
+ String[] domains = domain.split("\\,");
+ return ArrayUtils.contains(domains, getHost(t));
+ }
+
+ default boolean isRequestGrayServer(T t) {
+ ApiParam apiParam = getApiParam(t);
+ return apiParam.isGrayRequest();
+ }
+
+ String getHost(T t);
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java
new file mode 100644
index 00000000..1d4a6027
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/AppIdGrayUserBuilder.java
@@ -0,0 +1,19 @@
+package com.gitee.sop.gatewaycommon.loadbalancer.builder;
+
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+
+/**
+ * @author tanghc
+ */
+public class AppIdGrayUserBuilder implements GrayUserBuilder {
+
+ @Override
+ public String buildGrayUserKey(ApiParam apiParam) {
+ return apiParam.fetchAppKey();
+ }
+
+ @Override
+ public int order() {
+ return 0;
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java
new file mode 100644
index 00000000..7e23eecb
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/GrayUserBuilder.java
@@ -0,0 +1,24 @@
+package com.gitee.sop.gatewaycommon.loadbalancer.builder;
+
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+
+/**
+ * @author tanghc
+ */
+public interface GrayUserBuilder {
+
+ /**
+ * 获取灰度用户key
+ *
+ * @param apiParam apiParam
+ * @return 返回用户key
+ */
+ String buildGrayUserKey(ApiParam apiParam);
+
+ /**
+ * 优先级,数字小优先
+ *
+ * @return 返回数字
+ */
+ int order();
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java
new file mode 100644
index 00000000..c629b183
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/loadbalancer/builder/IpGrayUserBuilder.java
@@ -0,0 +1,19 @@
+package com.gitee.sop.gatewaycommon.loadbalancer.builder;
+
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+
+/**
+ * @author tanghc
+ */
+public class IpGrayUserBuilder implements GrayUserBuilder {
+
+ @Override
+ public String buildGrayUserKey(ApiParam apiParam) {
+ return apiParam.fetchIp();
+ }
+
+ @Override
+ public int order() {
+ return 1;
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java
index c8b8845a..f502e6ab 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java
@@ -4,25 +4,31 @@ import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.bean.BeanInitializer;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
+import com.gitee.sop.gatewaycommon.gateway.loadbalancer.NacosServerIntrospector;
import com.gitee.sop.gatewaycommon.limit.LimitManager;
import com.gitee.sop.gatewaycommon.loadbalancer.SopPropertiesFactory;
import com.gitee.sop.gatewaycommon.message.ErrorFactory;
import com.gitee.sop.gatewaycommon.param.ParameterFormatter;
-import com.gitee.sop.gatewaycommon.route.ServiceRouteListener;
import com.gitee.sop.gatewaycommon.route.EurekaRegistryListener;
import com.gitee.sop.gatewaycommon.route.NacosRegistryListener;
import com.gitee.sop.gatewaycommon.route.RegistryListener;
import com.gitee.sop.gatewaycommon.route.ServiceListener;
+import com.gitee.sop.gatewaycommon.route.ServiceRouteListener;
import com.gitee.sop.gatewaycommon.secret.IsvManager;
import com.gitee.sop.gatewaycommon.session.SessionManager;
import com.gitee.sop.gatewaycommon.validate.SignConfig;
import com.gitee.sop.gatewaycommon.validate.Validator;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
+import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
+import org.springframework.cloud.netflix.ribbon.eureka.EurekaServerIntrospector;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
@@ -34,11 +40,20 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import javax.annotation.PostConstruct;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
/**
* @author tanghc
*/
-public class AbstractConfiguration implements ApplicationContextAware {
+@Slf4j
+public class AbstractConfiguration implements ApplicationContextAware, ApplicationRunner {
+
+ private Lock lock = new ReentrantLock();
+ private Condition condition = lock.newCondition();
+
+ private volatile boolean isStartupCompleted;
@Autowired
protected Environment environment;
@@ -60,6 +75,17 @@ public class AbstractConfiguration implements ApplicationContextAware {
*/
@EventListener(classes = HeartbeatEvent.class)
public void listenNacosEvent(ApplicationEvent heartbeatEvent) {
+ // 没有启动完毕先等待
+ if (!isStartupCompleted) {
+ lock.lock();
+ try {
+ condition.await();
+ } catch (InterruptedException e) {
+ log.error("condition.await() error", e);
+ } finally {
+ lock.unlock();
+ }
+ }
registryListener.onEvent(heartbeatEvent);
}
@@ -159,6 +185,26 @@ public class AbstractConfiguration implements ApplicationContextAware {
return createCorsFilter();
}
+ /**
+ * 负责获取nacos实例的metadata
+ * @return
+ */
+ @Bean
+ @ConditionalOnProperty("spring.cloud.nacos.discovery.server-addr")
+ ServerIntrospector nacosServerIntrospector() {
+ return new NacosServerIntrospector();
+ }
+
+ /**
+ * 负责获取eureka实例的metadata
+ * @return
+ */
+ @Bean
+ @ConditionalOnProperty("eureka.client.serviceUrl.defaultZone")
+ ServerIntrospector eurekaServerIntrospector() {
+ return new EurekaServerIntrospector();
+ }
+
protected CorsFilter createCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
this.registerCorsConfiguration(source);
@@ -177,10 +223,22 @@ public class AbstractConfiguration implements ApplicationContextAware {
return corsConfiguration;
}
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ this.isStartupCompleted = true;
+ lock.lock();
+ condition.signalAll();
+ lock.unlock();
+ after();
+ }
+
@PostConstruct
- public final void after() {
+ private void post() {
EnvironmentContext.setEnvironment(environment);
SpringContext.setApplicationContext(applicationContext);
+ }
+
+ public final void after() {
if (RouteRepositoryContext.getRouteRepository() == null) {
throw new IllegalArgumentException("RouteRepositoryContext.setRouteRepository()方法未使用");
}
@@ -196,7 +254,6 @@ public class AbstractConfiguration implements ApplicationContextAware {
initMessage();
initBeanInitializer();
doAfter();
-
}
protected void initBeanInitializer() {
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteCache.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteCache.java
index e2dbddd1..0c0ace23 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteCache.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteCache.java
@@ -5,12 +5,9 @@ import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -55,21 +52,15 @@ public abstract class BaseRouteCache implements RouteLoad
}
serviceIdMd5Map.put(serviceId, newMd5);
- List extRouteDefinitionList = this.getExtRouteDefinitionList(serviceRouteInfo);
List routeDefinitionList = serviceRouteInfo.getRouteDefinitionList();
- int size = extRouteDefinitionList.size() + routeDefinitionList.size();
- List allRoutes = new ArrayList<>(size);
- if (CollectionUtils.isNotEmpty(extRouteDefinitionList)) {
- allRoutes.addAll(extRouteDefinitionList);
- }
- allRoutes.addAll(routeDefinitionList);
- for (RouteDefinition routeDefinition : allRoutes) {
+ for (RouteDefinition routeDefinition : routeDefinitionList) {
T targetRoute = this.buildTargetRoute(serviceRouteInfo, routeDefinition);
routeRepository.add(targetRoute);
if (log.isDebugEnabled()) {
log.debug("新增路由:{}", JSON.toJSONString(routeDefinition));
}
}
+ this.routeRepository.refresh();
callback.accept(null);
} catch (Exception e) {
log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e);
@@ -91,14 +82,6 @@ public abstract class BaseRouteCache implements RouteLoad
return DigestUtils.md5DigestAsHex(md5Source.getBytes(StandardCharsets.UTF_8));
}
- /**
- * 返回附加的路由选项
- * @return 返回附加的路由选项
- */
- protected List getExtRouteDefinitionList(ServiceRouteInfo serviceRouteInfo) {
- return Collections.emptyList();
- }
-
@Override
public void remove(String serviceId) {
serviceIdMd5Map.remove(serviceId);
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java
index 9e6df3be..abf3ae4f 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java
@@ -49,7 +49,7 @@ public class DefaultEnvGrayManager implements EnvGrayManager {
}
private ServiceGrayConfig getGrayConfig(String serviceId) {
- if (serviceId == null) {
+ if (serviceId == null || !instanceIdServiceIdMap.containsValue(serviceId)) {
return null;
}
return serviceGrayConfigMap.get(serviceId);
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java
index f05fa2eb..3fa1b20f 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/EnvironmentKeys.java
@@ -1,6 +1,6 @@
package com.gitee.sop.gatewaycommon.manager;
-import com.gitee.sop.gatewaycommon.loadbalancer.EnvironmentServerChooser;
+import com.gitee.sop.gatewaycommon.zuul.loadbalancer.EnvironmentServerChooser;
public enum EnvironmentKeys {
SPRING_PROFILES_ACTIVE("spring.profiles.active", "default"),
@@ -9,7 +9,7 @@ public enum EnvironmentKeys {
*/
SPRING_APPLICATION_NAME("spring.application.name"),
/**
- * 指定负载均衡规则类,默认使用com.gitee.sop.gateway.loadbalancer.PreEnvironmentServerChooser
+ * 指定负载均衡规则类
*/
ZUUL_CUSTOM_RULE_CLASSNAME("zuul.custom-rule-classname", EnvironmentServerChooser.class.getName()),
@@ -35,8 +35,11 @@ public enum EnvironmentKeys {
/**
* 排除其它微服务,正则形式,多个用英文逗号隔开
*/
- SOP_SERVICE_EXCLUDE_REGEX("sop.service.exclude-regex")
- ;
+ SOP_SERVICE_EXCLUDE_REGEX("sop.service.exclude-regex"),
+ /**
+ * 预发布域名
+ */
+ PRE_DOMAIN("pre.domain");
private String key;
private String defaultValue;
@@ -57,4 +60,8 @@ public enum EnvironmentKeys {
public String getValue() {
return EnvironmentContext.getValue(key, defaultValue);
}
+
+ public String getValue(String defaultValue) {
+ return EnvironmentContext.getValue(key, defaultValue);
+ }
}
\ No newline at end of file
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepository.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepository.java
index 8976090f..b6435e07 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepository.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepository.java
@@ -45,4 +45,9 @@ public interface RouteRepository {
* @param serviceId 服务id
*/
void deleteAll(String serviceId);
+
+ /**
+ * 刷新
+ */
+ default void refresh() {}
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepositoryContext.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepositoryContext.java
index f103f55e..ec4eb090 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepositoryContext.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteRepositoryContext.java
@@ -25,12 +25,14 @@ public class RouteRepositoryContext {
* 检查路由是否存在,不存在报错
* @param routeId 路由id
* @param errorEnum 报错信息
+ * @return 返回TargetRoute
*/
- public static void checkExist(String routeId, ErrorEnum errorEnum) {
+ public static TargetRoute checkExist(String routeId, ErrorEnum errorEnum) {
TargetRoute targetRoute = routeRepository.get(routeId);
if (targetRoute == null) {
throw errorEnum.getErrorMeta().getException();
}
+ return targetRoute;
}
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java
index ea5e43bd..1e3559b1 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ApiParam.java
@@ -14,6 +14,8 @@ import java.util.Map;
*/
public class ApiParam extends JSONObject implements Param {
+
+
public ApiParam() {
}
@@ -29,6 +31,8 @@ public class ApiParam extends JSONObject implements Param {
private String ip;
+ private boolean isGrayRequest;
+
private transient UploadContext uploadContext;
public void fitNameVersion() {
@@ -246,4 +250,12 @@ public class ApiParam extends JSONObject implements Param {
public String fetchIp() {
return ip;
}
+
+ public boolean isGrayRequest() {
+ return isGrayRequest;
+ }
+
+ public void setGrayRequest(boolean grayRequest) {
+ isGrayRequest = grayRequest;
+ }
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java
index c986bd2f..7361b758 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java
@@ -5,14 +5,15 @@ import com.alibaba.fastjson.JSONObject;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.bean.ErrorDefinition;
-import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.Isv;
+import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import com.gitee.sop.gatewaycommon.message.ErrorMeta;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.secret.IsvManager;
import com.gitee.sop.gatewaycommon.validate.alipay.AlipayConstants;
@@ -69,7 +70,7 @@ public abstract class BaseExecutorAdapter implements ResultExecutor
* @param t request
* @return 返回api参数
*/
- public abstract Map getApiParam(T t);
+ public abstract ApiParam getApiParam(T t);
@Override
public String mergeResult(T request, String serviceResult) {
@@ -91,12 +92,12 @@ public abstract class BaseExecutorAdapter implements ResultExecutor
responseData = JSON.parseObject(serviceResult);
responseData.put(GATEWAY_CODE_NAME, ISP_BIZ_ERROR.getCode());
responseData.put(GATEWAY_MSG_NAME, ISP_BIZ_ERROR.getError().getMsg());
- } else if(responseStatus == HttpStatus.NOT_FOUND.value()) {
+ } else if (responseStatus == HttpStatus.NOT_FOUND.value()) {
responseData = JSON.parseObject(serviceResult);
responseData.put(GATEWAY_CODE_NAME, ISV_MISSING_METHOD_META.getCode());
responseData.put(GATEWAY_MSG_NAME, ISV_MISSING_METHOD_META.getError().getCode());
} else {
- Map params = this.getApiParam(request);
+ ApiParam params = this.getApiParam(request);
log.error("微服务端报错,params:{}, 微服务返回结果:{}", params, serviceResult);
this.storeError(request, ErrorType.UNKNOWN);
// 微服务端有可能返回500错误
@@ -140,8 +141,11 @@ public abstract class BaseExecutorAdapter implements ResultExecutor
if (defaultSetting != null) {
return defaultSetting;
}
- ApiInfo apiInfo = this.getApiInfo(request);
- RouteDefinition baseRouteDefinition = apiInfo.gatewayRouteDefinition;
+ ApiParam params = this.getApiParam(request);
+ TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(params.fetchNameVersion());
+ RouteDefinition baseRouteDefinition = Optional.ofNullable(targetRoute)
+ .map(TargetRoute::getRouteDefinition)
+ .orElse(null);
return Optional.ofNullable(baseRouteDefinition)
.map(routeDefinition -> {
int mergeResult = baseRouteDefinition.getMergeResult();
@@ -151,11 +155,8 @@ public abstract class BaseExecutorAdapter implements ResultExecutor
}
protected ApiInfo getApiInfo(T request) {
- Map params = this.getApiParam(request);
- String name = this.getParamValue(params, ParamNames.API_NAME, SopConstants.UNKNOWN_METHOD);
- String version = this.getParamValue(params, ParamNames.VERSION_NAME, SopConstants.UNKNOWN_VERSION);
-
- TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(name + version);
+ ApiParam params = this.getApiParam(request);
+ TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(params.fetchNameVersion());
String serviceId = Optional.ofNullable(targetRoute)
.flatMap(route -> Optional.ofNullable(route.getServiceRouteInfo()))
@@ -167,8 +168,8 @@ public abstract class BaseExecutorAdapter implements ResultExecutor
.orElse(null);
ApiInfo apiInfo = new ApiInfo();
- apiInfo.name = name;
- apiInfo.version = version;
+ apiInfo.name = params.fetchName();
+ apiInfo.version = params.fetchVersion();
apiInfo.serviceId = serviceId;
apiInfo.gatewayRouteDefinition = baseRouteDefinition;
return apiInfo;
@@ -190,8 +191,8 @@ public abstract class BaseExecutorAdapter implements ResultExecutor
public String merge(T exchange, JSONObject responseData) {
JSONObject finalData = new JSONObject(true);
- Map params = this.getApiParam(exchange);
- String name = this.getParamValue(params, ParamNames.API_NAME, ERROR_METHOD);
+ ApiParam params = this.getApiParam(exchange);
+ String name = params.fetchName();
ApiConfig apiConfig = ApiConfig.getInstance();
// 点换成下划线
DataNameBuilder dataNameBuilder = apiConfig.getDataNameBuilder();
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutorForGateway.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutorForGateway.java
new file mode 100644
index 00000000..050309b1
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutorForGateway.java
@@ -0,0 +1,9 @@
+package com.gitee.sop.gatewaycommon.result;
+
+import org.springframework.web.server.ServerWebExchange;
+
+/**
+ * @author tanghc
+ */
+public interface ResultExecutorForGateway extends ResultExecutor {
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutorForZuul.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutorForZuul.java
new file mode 100644
index 00000000..12cbc89b
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/ResultExecutorForZuul.java
@@ -0,0 +1,9 @@
+package com.gitee.sop.gatewaycommon.result;
+
+import com.netflix.zuul.context.RequestContext;
+
+/**
+ * @author tanghc
+ */
+public interface ResultExecutorForZuul extends ResultExecutor {
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java
new file mode 100644
index 00000000..0b7715d5
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseForwardChooser.java
@@ -0,0 +1,66 @@
+package com.gitee.sop.gatewaycommon.route;
+
+import com.gitee.sop.gatewaycommon.bean.ApiConfig;
+import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
+import com.gitee.sop.gatewaycommon.bean.ApiParamAware;
+import com.gitee.sop.gatewaycommon.bean.TargetRoute;
+import com.gitee.sop.gatewaycommon.loadbalancer.builder.GrayUserBuilder;
+import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
+import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import org.apache.commons.lang3.BooleanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.annotation.PostConstruct;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author tanghc
+ */
+public abstract class BaseForwardChooser implements ForwardChooser, ApiParamAware {
+
+ @Autowired
+ private EnvGrayManager envGrayManager;
+
+ @Override
+ public ForwardInfo getForwardInfo(T t) {
+ ApiParam apiParam = getApiParam(t);
+ String nameVersion = apiParam.fetchNameVersion();
+ TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
+ RouteDefinition routeDefinitionOrig = targetRoute.getRouteDefinition();
+ String path = routeDefinitionOrig.getPath();
+ String version = apiParam.fetchVersion();
+ String serviceId = targetRoute.getServiceRouteInfo().fetchServiceIdLowerCase();
+ // 如果服务在灰度阶段,返回一个灰度版本号
+ String grayVersion = envGrayManager.getVersion(serviceId, nameVersion);
+ // 如果是灰度环境
+ if (grayVersion != null && isGrayUser(serviceId, apiParam)) {
+ String newNameVersion = apiParam.fetchName() + grayVersion;
+ TargetRoute targetRouteDest = RouteRepositoryContext.getRouteRepository().get(newNameVersion);
+ if (targetRouteDest != null) {
+ apiParam.setGrayRequest(true);
+ if (BooleanUtils.toBoolean(routeDefinitionOrig.getCompatibleMode())) {
+ version = grayVersion;
+ } else {
+ // 获取灰度接口
+ RouteDefinition routeDefinition = targetRouteDest.getRouteDefinition();
+ path = routeDefinition.getPath();
+ }
+ }
+ }
+ return new ForwardInfo(path, version);
+ }
+
+ protected boolean isGrayUser(String serviceId, ApiParam apiParam) {
+ List grayUserBuilders = ApiConfig.getInstance().getGrayUserBuilders();
+ for (GrayUserBuilder grayUserBuilder : grayUserBuilders) {
+ String userKey = grayUserBuilder.buildGrayUserKey(apiParam);
+ if (envGrayManager.containsKey(serviceId, userKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRegistryListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRegistryListener.java
index 4167e93b..39ef7da9 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRegistryListener.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRegistryListener.java
@@ -26,6 +26,7 @@ public abstract class BaseRegistryListener implements RegistryListener {
static {
EXCLUDE_SERVICE_ID_LIST.add("sop-gateway");
+ EXCLUDE_SERVICE_ID_LIST.add("sop-website");
EXCLUDE_SERVICE_ID_LIST.add("website-server");
}
@@ -37,7 +38,7 @@ public abstract class BaseRegistryListener implements RegistryListener {
*
* @param serviceId serviceId
*/
- public void removeRoutes(String serviceId) {
+ public synchronized void removeRoutes(String serviceId) {
serviceListener.onRemoveService(serviceId.toLowerCase());
}
@@ -46,7 +47,7 @@ public abstract class BaseRegistryListener implements RegistryListener {
*
* @param instance 服务实例
*/
- public void pullRoutes(InstanceDefinition instance) {
+ public synchronized void pullRoutes(InstanceDefinition instance) {
// serviceId统一小写
instance.setServiceId(instance.getServiceId().toLowerCase());
serviceListener.onAddInstance(instance);
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java
index 6eb37113..55f71a3a 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRegistryListener.java
@@ -1,8 +1,6 @@
package com.gitee.sop.gatewaycommon.route;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
-import com.gitee.sop.gatewaycommon.loadbalancer.EurekaEnvironmentServerChooser;
-import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Applications;
@@ -25,10 +23,6 @@ import java.util.stream.Collectors;
*/
public class EurekaRegistryListener extends BaseRegistryListener {
- static {
- System.setProperty(EnvironmentKeys.ZUUL_CUSTOM_RULE_CLASSNAME.getKey(), EurekaEnvironmentServerChooser.class.getName());
- }
-
private Set cacheServices = new HashSet<>();
@Override
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardChooser.java
new file mode 100644
index 00000000..346ac33d
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardChooser.java
@@ -0,0 +1,16 @@
+package com.gitee.sop.gatewaycommon.route;
+
+/**
+ * 转发选择
+ * @author tanghc
+ */
+public interface ForwardChooser {
+
+ /**
+ * 返回转发信息
+ * @param t 上下文
+ * @return 返回转发信息
+ */
+ ForwardInfo getForwardInfo(T t);
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardInfo.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardInfo.java
new file mode 100644
index 00000000..00c9333d
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ForwardInfo.java
@@ -0,0 +1,19 @@
+package com.gitee.sop.gatewaycommon.route;
+
+import lombok.Data;
+
+/**
+ * @author tanghc
+ */
+@Data
+public class ForwardInfo {
+ private String path;
+ private String version;
+ private String domain;
+
+ public ForwardInfo(String path, String version) {
+ this.path = path;
+ this.version = version;
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java
index 8bdf8f24..bfca1c63 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java
@@ -68,9 +68,10 @@ public class ApiValidator implements Validator {
@Override
public void validate(ApiParam param) {
checkIP(param);
- checkEnable(param);
+ TargetRoute targetRoute = checkEnable(param);
ApiConfig apiConfig = ApiContext.getApiConfig();
- if (apiConfig.isIgnoreValidate() || param.fetchIgnoreValidate()) {
+ if (apiConfig.isIgnoreValidate()
+ || BooleanUtils.toBoolean(targetRoute.getRouteDefinition().getIgnoreValidate())) {
if (log.isDebugEnabled()) {
log.debug("忽略所有验证(ignoreValidate=true), name:{}, version:{}", param.fetchName(), param.fetchVersion());
}
@@ -103,7 +104,7 @@ public class ApiValidator implements Validator {
*
* @param param 接口参数
*/
- protected void checkEnable(ApiParam param) {
+ protected TargetRoute checkEnable(ApiParam param) {
String name = param.fetchName();
if (name == null) {
throw ErrorEnum.ISV_MISSING_METHOD.getErrorMeta().getException();
@@ -114,12 +115,13 @@ public class ApiValidator implements Validator {
}
String routeId = param.fetchNameVersion();
// 检查路由是否存在
- RouteRepositoryContext.checkExist(routeId, ErrorEnum.ISV_INVALID_METHOD);
+ TargetRoute targetRoute = RouteRepositoryContext.checkExist(routeId, ErrorEnum.ISV_INVALID_METHOD);
// 检查路由是否启用
RouteConfig routeConfig = routeConfigManager.get(routeId);
if (!routeConfig.enable()) {
throw ErrorEnum.ISP_API_DISABLED.getErrorMeta().getException();
}
+ return targetRoute;
}
/**
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/ValidateService.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/ValidateService.java
index 3ad55621..c5c69032 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/ValidateService.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/ValidateService.java
@@ -37,7 +37,13 @@ public class ValidateService {
RequestContext currentContext = RequestContext.getCurrentContext();
currentContext.setRequest(RequestUtil.wrapRequest(request));
currentContext.setResponse(response);
- doValidate(currentContext, callback);
+ // 解析参数
+ ApiParam param = ZuulContext.getApiParam();
+ if (param == null) {
+ param = paramBuilder.build(currentContext);
+ ZuulContext.setApiParam(param);
+ }
+ doValidate(currentContext, param, callback);
}
/**
@@ -45,10 +51,7 @@ public class ValidateService {
*
* @param currentContext currentContext
*/
- private void doValidate(RequestContext currentContext, ValidateCallback callback) {
- // 解析参数
- ApiParam param = paramBuilder.build(currentContext);
- ZuulContext.setApiParam(param);
+ private void doValidate(RequestContext currentContext, ApiParam param, ValidateCallback callback) {
Exception error = null;
// 验证操作,这里有负责验证签名参数
try {
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java
index 3b6dbc9f..258f5f70 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java
@@ -8,17 +8,18 @@ import com.gitee.sop.gatewaycommon.param.ParamBuilder;
import com.gitee.sop.gatewaycommon.zuul.ValidateService;
import com.gitee.sop.gatewaycommon.zuul.controller.ConfigChannelController;
import com.gitee.sop.gatewaycommon.zuul.controller.ErrorLogController;
+import com.gitee.sop.gatewaycommon.zuul.controller.ZuulErrorController;
import com.gitee.sop.gatewaycommon.zuul.controller.ZuulIndexController;
import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.FormBodyWrapperFilterExt;
import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter;
-import com.gitee.sop.gatewaycommon.zuul.filter.PreEnvGrayFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter;
import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt;
import com.gitee.sop.gatewaycommon.zuul.route.SopRouteLocator;
+import com.gitee.sop.gatewaycommon.zuul.route.ZuulForwardChooser;
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteCache;
import com.gitee.sop.gatewaycommon.zuul.route.ZuulRouteRepository;
import com.netflix.zuul.context.RequestContext;
@@ -26,7 +27,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
-import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.context.annotation.Bean;
@@ -89,22 +89,28 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return new Servlet30WrapperFilterExt();
}
+ @Bean
+ SopRouteLocator sopRouteLocator() {
+ return new SopRouteLocator();
+ }
+
/**
* 选取路由
- * @param zuulRouteRepository
+ * @param sopRouteLocator
* @param proxyRequestHelper
* @return
*/
@Bean
- PreDecorationFilter preDecorationFilter(ZuulRouteRepository zuulRouteRepository, ProxyRequestHelper proxyRequestHelper) {
+ PreDecorationFilter preDecorationFilter(SopRouteLocator sopRouteLocator, ProxyRequestHelper proxyRequestHelper) {
// 自定义路由
- RouteLocator routeLocator = new SopRouteLocator(zuulRouteRepository);
- return new PreDecorationFilter(routeLocator,
+ return new PreDecorationFilter(sopRouteLocator,
this.server.getServlet().getContextPath(),
this.zuulProperties,
proxyRequestHelper);
}
+
+
/**
* 路由管理
* @param zuulRouteRepository 路由仓库
@@ -140,14 +146,6 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return new PreLimitFilter();
}
- /**
- * 决定版本号
- */
- @Bean
- PreEnvGrayFilter preEnvGrayFilter() {
- return new PreEnvGrayFilter();
- }
-
/**
* 错误处理扩展
*/
@@ -169,9 +167,13 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
* 统一错误处理
*/
@Bean
- @ConditionalOnMissingBean
- ZuulErrorController baseZuulController() {
+ ZuulErrorController zuulErrorController() {
return ApiContext.getApiConfig().getZuulErrorController();
}
+ @Bean
+ ZuulForwardChooser zuulForwardChooser() {
+ return new ZuulForwardChooser();
+ }
+
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ConfigChannelController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ConfigChannelController.java
index 3ff5371a..859af8a1 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ConfigChannelController.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ConfigChannelController.java
@@ -40,7 +40,7 @@ public class ConfigChannelController {
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ROUTE_CONFIG, RouteConfigManager.class);
}
- @Value("${zuul.secret}")
+ @Value("${sop.secret}")
private String secret;
@PostMapping("/configChannelMsg")
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ErrorLogController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ErrorLogController.java
index 3c773afb..c4907461 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ErrorLogController.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ErrorLogController.java
@@ -1,72 +1,23 @@
package com.gitee.sop.gatewaycommon.zuul.controller;
-import com.gitee.sop.gatewaycommon.bean.ApiConfig;
-import com.gitee.sop.gatewaycommon.bean.ErrorEntity;
-import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager;
+import com.gitee.sop.gatewaycommon.bean.BaseErrorLogController;
import com.gitee.sop.gatewaycommon.param.ApiParam;
-import com.gitee.sop.gatewaycommon.result.ApiResult;
-import com.gitee.sop.gatewaycommon.result.JsonResult;
import com.gitee.sop.gatewaycommon.util.RequestUtil;
-import com.gitee.sop.gatewaycommon.validate.taobao.TaobaoSigner;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
-import java.util.Collection;
import java.util.Map;
/**
* @author tanghc
*/
-@Controller
-public class ErrorLogController {
+@RestController
+public class ErrorLogController extends BaseErrorLogController {
- TaobaoSigner signer = new TaobaoSigner();
-
- @Value("${zuul.secret}")
- private String secret;
-
- @GetMapping("listErrors")
- public ApiResult listErrors(HttpServletRequest request) {
- try {
- this.check(request);
- ServiceErrorManager serviceErrorManager = ApiConfig.getInstance().getServiceErrorManager();
- Collection allErrors = serviceErrorManager.listAllErrors();
- JsonResult apiResult = new JsonResult();
- apiResult.setData(allErrors);
- return apiResult;
- } catch (Exception e) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode("505050");
- apiResult.setMsg(e.getMessage());
- return apiResult;
- }
- }
-
- @GetMapping("clearErrors")
- public ApiResult clearErrors(HttpServletRequest request) {
- try {
- this.check(request);
- ServiceErrorManager serviceErrorManager = ApiConfig.getInstance().getServiceErrorManager();
- serviceErrorManager.clear();
- return new ApiResult();
- } catch (Exception e) {
- ApiResult apiResult = new ApiResult();
- apiResult.setCode("505050");
- apiResult.setMsg(e.getMessage());
- return apiResult;
- }
- }
-
- private void check(HttpServletRequest request) {
+ @Override
+ protected ApiParam getApiParam(HttpServletRequest request) {
Map params = RequestUtil.convertRequestParamsToMap(request);
- ApiParam apiParam = ApiParam.build(params);
- boolean right = signer.checkSign(apiParam, secret);
- if (!right) {
- throw new RuntimeException("签名校验失败");
- }
+ return ApiParam.build(params);
}
-
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/RestServlet.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/RestServlet.java
deleted file mode 100644
index 1a1a484e..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/RestServlet.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.gitee.sop.gatewaycommon.zuul.controller;
-
-import com.gitee.sop.gatewaycommon.bean.SopConstants;
-import org.springframework.beans.factory.annotation.Value;
-
-import javax.servlet.ServletException;
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * 传统web开发入口
- * @author tanghc
- */
-//@WebServlet(urlPatterns = "/rest/*")
-public class RestServlet extends HttpServlet {
-
- private static final String EMPTY_VERSION = "";
-
- @Value("${zuul.servlet-path:/zuul}")
- private String path;
-
- @Value("${sop.restful.path:/rest}")
- private String restPath;
-
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- doPost(request, response);
- }
-
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- String url = request.getRequestURL().toString();
- int index = url.indexOf(restPath);
- // 取/rest的后面部分
- String path = url.substring(index + restPath.length());
- request.setAttribute(SopConstants.REDIRECT_METHOD_KEY, path);
- request.setAttribute(SopConstants.REDIRECT_VERSION_KEY, EMPTY_VERSION);
- request.setAttribute(SopConstants.SOP_NOT_MERGE, true);
- request.getRequestDispatcher(this.path).forward(request, response);
- }
-
-}
\ No newline at end of file
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/ZuulErrorController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulErrorController.java
similarity index 79%
rename from sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/ZuulErrorController.java
rename to sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulErrorController.java
index cb20a6ae..ce682db5 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/ZuulErrorController.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulErrorController.java
@@ -1,4 +1,4 @@
-package com.gitee.sop.gatewaycommon.zuul.configuration;
+package com.gitee.sop.gatewaycommon.zuul.controller;
import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.result.ResultExecutor;
@@ -6,30 +6,26 @@ import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorController;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
- * 处理网关自身异常
+ * zuul的异常处理
*
* @author tanghc
*/
-@Controller
@Slf4j
+@RestController
public class ZuulErrorController implements ErrorController {
- private static final String ERROR_PATH = "/error";
-
/**
* 错误最终会到这里来
*/
- @RequestMapping(ERROR_PATH)
- @ResponseBody
+ @RequestMapping("/error")
public Object error(HttpServletRequest request, HttpServletResponse response) {
RequestContext ctx = RequestContext.getCurrentContext();
if (ctx.getResponse() == null) {
@@ -51,6 +47,6 @@ public class ZuulErrorController implements ErrorController {
@Override
public String getErrorPath() {
- return ERROR_PATH;
+ return "/error";
}
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulIndexController.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulIndexController.java
index ac1606e4..bc7ebd27 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulIndexController.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/controller/ZuulIndexController.java
@@ -6,7 +6,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
@@ -75,15 +74,4 @@ public class ZuulIndexController {
request.getRequestDispatcher(this.path).forward(request, response);
}
- @RequestMapping("/{method}/{version}/")
- public void redirect(
- @PathVariable("method") String method
- , @PathVariable("version") String version
- , HttpServletRequest request
- , HttpServletResponse response
- ) {
- request.setAttribute(SopConstants.REDIRECT_METHOD_KEY, method);
- request.setAttribute(SopConstants.REDIRECT_VERSION_KEY, version);
- validateService.validate(request, response, callback);
- }
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreEnvGrayFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreEnvGrayFilter.java
index bc5e00de..cd00823f 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreEnvGrayFilter.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreEnvGrayFilter.java
@@ -14,7 +14,10 @@ import org.springframework.beans.factory.annotation.Autowired;
* 灰度发布判断,改变版本号
*
* @author tanghc
+ * @deprecated
+ * @see com.gitee.sop.gatewaycommon.zuul.route.ZuulForwardChooser
*/
+@Deprecated
public class PreEnvGrayFilter extends BaseZuulFilter {
@Autowired
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java
deleted file mode 100644
index e92a2fb2..00000000
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/BaseServerChooser.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.gitee.sop.gatewaycommon.zuul.loadbalancer;
-
-import com.gitee.sop.gatewaycommon.bean.SpringContext;
-import com.gitee.sop.gatewaycommon.manager.EnvGrayManager;
-import com.google.common.base.Optional;
-import com.netflix.loadbalancer.ILoadBalancer;
-import com.netflix.loadbalancer.Server;
-import com.netflix.loadbalancer.ZoneAvoidanceRule;
-import com.netflix.zuul.context.RequestContext;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang.ArrayUtils;
-import org.springframework.core.env.Environment;
-import org.springframework.util.StringUtils;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 服务实例选择器
- *
- * @author tanghc
- */
-@Slf4j
-public abstract class BaseServerChooser extends ZoneAvoidanceRule {
-
-
- /**
- * 是否是预发布服务器
- * @param server 服务器
- * @return true:是
- */
- protected abstract boolean isPreServer(Server server);
-
- /**
- * 是否是灰度发布服务器
- * @param server 服务器
- * @return true:是
- */
- protected abstract boolean isGrayServer(Server server);
-
- /**
- * 能否访问预发布
- * @param server 预发布服务器
- * @param request request
- * @return true:能
- */
- protected abstract boolean canVisitPre(Server server, HttpServletRequest request);
-
-
- @Override
- public Server choose(Object key) {
- ILoadBalancer lb = getLoadBalancer();
- // 获取服务实例列表
- List servers = lb.getReachableServers();
- RequestContext currentContext = RequestContext.getCurrentContext();
- // 存放预发服务器
- List preServers = new ArrayList<>(4);
- // 存放灰度发布服务器
- List grayServers = new ArrayList<>(4);
- // 存放非预发服务器
- List notPreServers = new ArrayList<>(4);
-
- for (Server server : servers) {
- // 是否开启了预发模式
- if (this.isPreServer(server)) {
- preServers.add(server);
- } else if (this.isGrayServer(server)) {
- grayServers.add(server);
- } else {
- notPreServers.add(server);
- }
- }
- notPreServers.addAll(grayServers);
- // 如果没有开启预发布服务和灰度发布,直接用默认的方式
- if (preServers.isEmpty() && grayServers.isEmpty()) {
- return super.choose(key);
- }
- // 如果是从预发布域名访问过来,则认为是预发布请求
- if (this.isRequestFromPreDomain(currentContext.getRequest())) {
- return doChoose(preServers, key);
- }
- // 如果是灰度请求
- if (this.isRequestGrayServer(currentContext)) {
- return doChoose(grayServers, key);
- }
-
- // 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器
- return doChoose(notPreServers, key);
- }
-
- /**
- * 通过判断hostname来确定是否是预发布请求
- *
- * @param t t
- * @return 返回true:可以进入到预发环境
- */
- protected boolean isRequestFromPreDomain(HttpServletRequest t) {
- String domain = SpringContext.getBean(Environment.class).getProperty("pre.domain");
- if (StringUtils.isEmpty(domain)) {
- return false;
- }
- String[] domains = domain.split("\\,");
- return ArrayUtils.contains(domains, getHost(t));
- }
-
- protected boolean isRequestGrayServer(RequestContext t) {
- return t.get(EnvGrayManager.ENV_GRAY) != null;
- }
-
- protected String getHost(HttpServletRequest t) {
- return t.getServerName();
- }
-
- protected Server doChoose(List servers, Object key) {
- Optional server = getPredicate().chooseRoundRobinAfterFiltering(servers, key);
- if (server.isPresent()) {
- return server.get();
- } else {
- return null;
- }
- }
-
-}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java
new file mode 100644
index 00000000..a9a6c477
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/EnvironmentServerChooser.java
@@ -0,0 +1,55 @@
+package com.gitee.sop.gatewaycommon.zuul.loadbalancer;
+
+import com.gitee.sop.gatewaycommon.loadbalancer.ServerChooserContext;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
+import com.google.common.base.Optional;
+import com.netflix.loadbalancer.Server;
+import com.netflix.loadbalancer.ZoneAvoidanceRule;
+import com.netflix.zuul.context.RequestContext;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * 预发布、灰度环境选择,参考自:https://segmentfault.com/a/1190000017412946
+ *
+ * @author tanghc
+ */
+@Slf4j
+public class EnvironmentServerChooser extends ZoneAvoidanceRule implements ServerChooserContext {
+
+ private ZuulLoadBalanceServerChooser loadBalanceServerChooser = new ZuulLoadBalanceServerChooser();
+
+ @Override
+ public String getHost(HttpServletRequest request) {
+ return request.getServerName();
+ }
+
+ @Override
+ public ApiParam getApiParam(HttpServletRequest request) {
+ return ZuulContext.getApiParam();
+ }
+
+ @Override
+ public Server choose(Object key) {
+ return loadBalanceServerChooser.choose(
+ String.valueOf(key)
+ , RequestContext.getCurrentContext().getRequest()
+ , getLoadBalancer()
+ , () -> super.choose(key)
+ , (servers) -> this.doChoose(servers, key)
+ );
+ }
+
+ protected Server doChoose(List servers, Object key) {
+ Optional server = getPredicate().chooseRoundRobinAfterFiltering(servers, key);
+ if (server.isPresent()) {
+ return server.get();
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java
new file mode 100644
index 00000000..b1046ee9
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/loadbalancer/ZuulLoadBalanceServerChooser.java
@@ -0,0 +1,24 @@
+package com.gitee.sop.gatewaycommon.zuul.loadbalancer;
+
+import com.gitee.sop.gatewaycommon.loadbalancer.LoadBalanceServerChooser;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
+import com.netflix.loadbalancer.Server;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author tanghc
+ */
+public class ZuulLoadBalanceServerChooser extends LoadBalanceServerChooser {
+
+ @Override
+ public String getHost(HttpServletRequest request) {
+ return request.getServerName();
+ }
+
+ @Override
+ public ApiParam getApiParam(HttpServletRequest request) {
+ return ZuulContext.getApiParam();
+ }
+}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/result/ZuulResultExecutor.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/result/ZuulResultExecutor.java
index 9cfd0cd7..ad4de22d 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/result/ZuulResultExecutor.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/result/ZuulResultExecutor.java
@@ -6,7 +6,9 @@ import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.exception.ApiException;
import com.gitee.sop.gatewaycommon.message.Error;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
+import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.result.BaseExecutorAdapter;
+import com.gitee.sop.gatewaycommon.result.ResultExecutorForZuul;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import com.netflix.util.Pair;
import com.netflix.zuul.context.RequestContext;
@@ -14,13 +16,12 @@ import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
-import java.util.Map;
/**
* @author tanghc
*/
@Slf4j
-public class ZuulResultExecutor extends BaseExecutorAdapter {
+public class ZuulResultExecutor extends BaseExecutorAdapter implements ResultExecutorForZuul {
@Override
protected boolean isMergeResult(RequestContext request) {
@@ -62,7 +63,7 @@ public class ZuulResultExecutor extends BaseExecutorAdapter getApiParam(RequestContext requestContext) {
+ public ApiParam getApiParam(RequestContext requestContext) {
return ZuulContext.getApiParam();
}
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java
index ce07b1ca..edb41374 100644
--- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java
@@ -2,7 +2,11 @@ package com.gitee.sop.gatewaycommon.zuul.route;
import com.gitee.sop.gatewaycommon.bean.AbstractTargetRoute;
import com.gitee.sop.gatewaycommon.param.ApiParam;
+import com.gitee.sop.gatewaycommon.route.ForwardInfo;
+import com.gitee.sop.gatewaycommon.param.ParamNames;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
+import com.netflix.zuul.context.RequestContext;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.core.Ordered;
@@ -19,11 +23,11 @@ import java.util.stream.Collectors;
*/
public class SopRouteLocator implements RouteLocator, Ordered {
+ @Autowired
private ZuulRouteRepository zuulRouteRepository;
- public SopRouteLocator(ZuulRouteRepository zuulRouteRepository) {
- this.zuulRouteRepository = zuulRouteRepository;
- }
+ @Autowired
+ private ZuulForwardChooser zuulForwardChooser;
@Override
public Collection getIgnoredPaths() {
@@ -52,7 +56,13 @@ public class SopRouteLocator implements RouteLocator, Ordered {
if (zuulTargetRoute == null) {
return null;
}
- return zuulTargetRoute.getTargetRouteDefinition();
+ Route targetRouteDefinition = zuulTargetRoute.getTargetRouteDefinition();
+ ForwardInfo forwardInfo = zuulForwardChooser.getForwardInfo(RequestContext.getCurrentContext());
+ String forwardPath = forwardInfo.getPath();
+ targetRouteDefinition.setPath(forwardPath);
+ String versionInHead = forwardInfo.getVersion();
+ RequestContext.getCurrentContext().addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, versionInHead);
+ return targetRouteDefinition;
}
@Override
diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java
new file mode 100644
index 00000000..625d129f
--- /dev/null
+++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulForwardChooser.java
@@ -0,0 +1,18 @@
+package com.gitee.sop.gatewaycommon.zuul.route;
+
+import com.gitee.sop.gatewaycommon.param.ApiParam;
+import com.gitee.sop.gatewaycommon.route.BaseForwardChooser;
+import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
+import com.netflix.zuul.context.RequestContext;
+
+/**
+ * @author tanghc
+ */
+public class ZuulForwardChooser extends BaseForwardChooser {
+
+ @Override
+ public ApiParam getApiParam(RequestContext requestContext) {
+ return ZuulContext.getApiParam();
+ }
+
+}
diff --git a/sop-common/sop-service-common/pom.xml b/sop-common/sop-service-common/pom.xml
index d471851b..e0558fc1 100644
--- a/sop-common/sop-service-common/pom.xml
+++ b/sop-common/sop-service-common/pom.xml
@@ -6,11 +6,11 @@
com.gitee.sop
sop-common
- 2.5.12-SNAPSHOT
+ 3.0.0-SNAPSHOT
../pom.xml
sop-service-common
- 2.5.12-SNAPSHOT
+ 3.0.0-SNAPSHOT
jar
sop-service-common
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java
index 85d1f9a3..d200c4b4 100644
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java
+++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceApiInfo.java
@@ -34,6 +34,8 @@ public class ServiceApiInfo {
private int permission;
/** 是否需要token */
private int needToken;
+ /** 是否是兼容模式,即使用了@ApiAbility注解 */
+ private int compatibleMode;
/** 是否是原始Mapping */
private boolean originalMapping;
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaBuilder.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaBuilder.java
index 8f3ecb17..55c2bf58 100644
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaBuilder.java
+++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ApiMetaBuilder.java
@@ -95,6 +95,7 @@ public class ApiMetaBuilder {
apiMeta.setMergeResult(BooleanUtils.toInteger(apiMappingInfo.isMergeResult()));
apiMeta.setPermission(BooleanUtils.toInteger(apiMappingInfo.isPermission()));
apiMeta.setNeedToken(BooleanUtils.toInteger(apiMappingInfo.isNeedToken()));
+ apiMeta.setCompatibleMode(BooleanUtils.toInteger(apiMappingInfo.isCompatibleMode()));
return apiMeta;
} else {
if (!ServiceContext.getCurrentContext().getBoolean(ServiceContext.RESTFUL_KEY, false)) {
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceRouteInfoHandler.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceRouteInfoHandler.java
deleted file mode 100644
index 882963ea..00000000
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceRouteInfoHandler.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.gitee.sop.servercommon.manager;
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-/**
- * @author tanghc
- */
-public interface ServiceRouteInfoHandler {
-}
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java
index 9f6467fd..1d706005 100644
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java
+++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingHandlerMapping.java
@@ -5,6 +5,7 @@ import com.gitee.sop.servercommon.annotation.ApiMapping;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.bean.ServiceContext;
import com.gitee.sop.servercommon.util.OpenUtil;
+import org.apache.commons.lang.StringUtils;
import org.springframework.core.PriorityOrdered;
import org.springframework.util.StringValueResolver;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
@@ -18,7 +19,6 @@ import java.lang.reflect.Method;
*/
public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping implements PriorityOrdered {
- private static StringValueResolver stringValueResolver = new ApiMappingStringValueResolver();
private static StringValueResolver stringValueResolverMVC = new ApiMappingStringValueResolverMVC();
@Override
@@ -29,7 +29,11 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
ApiAbility apiAbility = OpenUtil.getAnnotationFromMethodOrClass(method, ApiAbility.class);
StringValueResolver valueResolver = null;
if (apiMapping != null) {
- valueResolver = stringValueResolver;
+ String version = apiMapping.version();
+ if (StringUtils.isBlank(version)) {
+ version = ServiceConfig.getInstance().getDefaultVersion();
+ }
+ valueResolver = new ApiMappingStringValueResolverVersion(version);
}
if (isMvc || apiAbility != null) {
valueResolver = stringValueResolverMVC;
@@ -46,7 +50,8 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
boolean ignoreValidate;
boolean mergeResult;
boolean permission;
- boolean needToken = false;
+ boolean needToken;
+ boolean compatibleMode = false;
ApiMapping apiMapping = method.getAnnotation(ApiMapping.class);
if (apiMapping != null) {
name = apiMapping.value()[0];
@@ -63,6 +68,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
mergeResult = apiAbility.mergeResult();
permission = apiAbility.permission();
needToken = apiAbility.needToken();
+ compatibleMode = true;
} else {
return super.getCustomMethodCondition(method);
}
@@ -87,6 +93,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
apiMappingInfo.setMergeResult(mergeResult);
apiMappingInfo.setPermission(permission);
apiMappingInfo.setNeedToken(needToken);
+ apiMappingInfo.setCompatibleMode(compatibleMode);
logger.info("注册接口,name:" + method + ", version:" + version);
return new ApiMappingRequestCondition(apiMappingInfo);
}
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java
index cc2dfb3d..765de153 100644
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java
+++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingInfo.java
@@ -13,6 +13,8 @@ public class ApiMappingInfo {
private boolean mergeResult;
private boolean permission;
private boolean needToken;
+ private boolean compatibleMode;
+
public ApiMappingInfo(String name, String version) {
this.name = name;
diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java
index c64ecadf..6ef894ea 100644
--- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java
+++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/mapping/ApiMappingRequestCondition.java
@@ -37,6 +37,11 @@ public class ApiMappingRequestCondition implements RequestCondition
com.gitee.sop
sop-service-common
- 2.5.12-SNAPSHOT
+ 3.0.0-SNAPSHOT
com.gitee.sop
diff --git a/sop-example/sop-easyopen/pom.xml b/sop-example/sop-easyopen/pom.xml
index 5c2099d7..8140f57a 100644
--- a/sop-example/sop-easyopen/pom.xml
+++ b/sop-example/sop-easyopen/pom.xml
@@ -29,7 +29,7 @@
com.gitee.sop
sop-service-common
- 2.5.12-SNAPSHOT
+ 3.0.0-SNAPSHOT
diff --git a/sop-example/sop-story/sop-story-web/pom.xml b/sop-example/sop-story/sop-story-web/pom.xml
index f39b5429..7b7c6ba6 100644
--- a/sop-example/sop-story/sop-story-web/pom.xml
+++ b/sop-example/sop-story/sop-story-web/pom.xml
@@ -28,7 +28,7 @@
com.gitee.sop
sop-service-common
- 2.5.12-SNAPSHOT
+ 3.0.0-SNAPSHOT
com.gitee.sop
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java
index b0530de1..f7510610 100644
--- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java
@@ -17,6 +17,8 @@ import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -39,6 +41,9 @@ import java.util.List;
@Api(tags = "故事接口")
public class AlipayController {
+ @Autowired
+ private Environment environment;
+
// http://localhost:2222/story_get
// 原生的接口,可正常调用
@RequestMapping("story_get")
@@ -49,7 +54,7 @@ public class AlipayController {
return result;
}
- // http://localhost:2222/story.get/
+ // http://localhost:2222/story.get/1.0/
// 接口名,使用默认版本号
@ApiMapping(value = "story.get")
public StoryResult storyget() {
@@ -62,7 +67,7 @@ public class AlipayController {
return result;
}
- // http://localhost:2222/story.get/?version=1.1
+ // http://localhost:2222/story.get/1.1/
// 接口名 + 版本号
@ApiMapping(value = "story.get", version = "1.1")
public StoryResult getStory2() {
@@ -72,7 +77,7 @@ public class AlipayController {
return result;
}
- // http://localhost:2222/story.get/?name=111&version=2.0
+ // http://localhost:2222/story.get/2.0/?name=111
// 接口名 + 版本号
// StoryParam对应biz_content内容
@ApiMapping(value = "story.get", version = "2.0")
@@ -174,13 +179,13 @@ public class AlipayController {
return story;
}
- // http://localhost:2222/alipay.story.get/
- @ApiOperation(value="获取故事信息2", notes = "获取故事信息2的详细信息")
+ // http://localhost:2222/alipay.story.get/1.0/?name=Jim
+ @ApiOperation(value="获取故事信息", notes = "获取故事信息的详细信息")
@ApiMapping(value = "alipay.story.get")
public StoryResult getStory(StoryParam param) {
StoryResult story = new StoryResult();
story.setId(1L);
- story.setName("海底小纵队(alipay.story.get1.0), param:" + param);
+ story.setName("海底小纵队(alipay.story.get1.0), port:" + environment.getProperty("server.port") + ", param:" + param);
return story;
}
@@ -188,6 +193,7 @@ public class AlipayController {
* @param param 对应biz_content中的内容,并自动JSR-303校验
* @return
*/
+ @ApiOperation(value="获取故事信息", notes = "获取故事信息的详细信息")
@ApiMapping(value = "alipay.story.get", version = "1.2")
public StoryResult getStory11(StoryParam param) {
StoryResult story2 = new StoryResult();
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/FileUploadDemoController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/FileUploadDemoController.java
index ff57a354..e5854db1 100644
--- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/FileUploadDemoController.java
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/FileUploadDemoController.java
@@ -34,7 +34,6 @@ public class FileUploadDemoController {
@ApiOperation(value = "文件上传例1", notes = "上传文件demo")
@ApiMapping(value = "demo.file.upload")
public FileUploadResult file1(FileUploadParam param) {
- System.out.println(param.getRemark());
// 获取上传的文件
MultipartFile file1 = param.getFile1();
MultipartFile file2 = param.getFile2();
@@ -43,6 +42,7 @@ public class FileUploadDemoController {
FileUploadResult.FileMeta fileMeta1 = buildFileMeta(file1);
FileUploadResult.FileMeta fileMeta2 = buildFileMeta(file2);
+ result.setRemark(param.getRemark());
result.getFiles().add(fileMeta1);
result.getFiles().add(fileMeta2);
return result;
diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/result/FileUploadResult.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/result/FileUploadResult.java
index 447292ad..11f20176 100644
--- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/result/FileUploadResult.java
+++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/result/FileUploadResult.java
@@ -13,6 +13,7 @@ import java.util.List;
public class FileUploadResult {
private List files = new ArrayList();
+ private String remark;
@Data
public static class FileMeta {
diff --git a/sop-gateway/pom.xml b/sop-gateway/pom.xml
index 2f5c34c6..2b18e01e 100644
--- a/sop-gateway/pom.xml
+++ b/sop-gateway/pom.xml
@@ -26,23 +26,17 @@