|
@ -0,0 +1,251 @@
|
|
|
package com.yihu.jw.gateway.config;
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
|
|
|
import org.springframework.cloud.netflix.zuul.filters.Route;
|
|
|
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
|
|
|
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
|
|
|
import org.springframework.cloud.netflix.zuul.util.RequestUtils;
|
|
|
import org.springframework.core.Ordered;
|
|
|
import org.springframework.util.AntPathMatcher;
|
|
|
import org.springframework.util.PathMatcher;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
|
|
|
/**
|
|
|
* Created by progr1mmer on 2018/8/24.
|
|
|
*/
|
|
|
public class ComplexRouteLocator implements RefreshableRouteLocator, Ordered {
|
|
|
|
|
|
private static final Log log = LogFactory.getLog(SimpleRouteLocator.class);
|
|
|
|
|
|
private static final int DEFAULT_ORDER = 0;
|
|
|
|
|
|
private ZuulProperties properties;
|
|
|
|
|
|
private PathMatcher pathMatcher = new AntPathMatcher();
|
|
|
|
|
|
private String dispatcherServletPath = "/";
|
|
|
|
|
|
private String zuulServletPath;
|
|
|
|
|
|
private AtomicReference<Map<String, ZuulProperties.ZuulRoute>> routes = new AtomicReference<>();
|
|
|
private int order = DEFAULT_ORDER;
|
|
|
|
|
|
private final JdbcZuulRouteService jdbcZuulRouteService;
|
|
|
private final boolean configPriority;
|
|
|
|
|
|
public ComplexRouteLocator(
|
|
|
String servletPath,
|
|
|
ZuulProperties properties,
|
|
|
JdbcZuulRouteService jdbcZuulRouteService,
|
|
|
boolean configPriority) {
|
|
|
this.properties = properties;
|
|
|
if (StringUtils.hasText(servletPath)) {
|
|
|
this.dispatcherServletPath = servletPath;
|
|
|
}
|
|
|
|
|
|
this.zuulServletPath = properties.getServletPath();
|
|
|
this.jdbcZuulRouteService = jdbcZuulRouteService;
|
|
|
this.configPriority = configPriority;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<Route> getRoutes() {
|
|
|
List<Route> values = new ArrayList<>();
|
|
|
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : getRoutesMap().entrySet()) {
|
|
|
ZuulProperties.ZuulRoute route = entry.getValue();
|
|
|
String path = route.getPath();
|
|
|
values.add(getRoute(route, path));
|
|
|
}
|
|
|
return values;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Collection<String> getIgnoredPaths() {
|
|
|
return this.properties.getIgnoredPatterns();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Route getMatchingRoute(final String path) {
|
|
|
|
|
|
return getSimpleMatchingRoute(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
protected Map<String, ZuulProperties.ZuulRoute> getRoutesMap() {
|
|
|
if (this.routes.get() == null) {
|
|
|
this.routes.set(locateRoutes());
|
|
|
}
|
|
|
return this.routes.get();
|
|
|
}
|
|
|
|
|
|
protected Route getSimpleMatchingRoute(final String path) {
|
|
|
if (log.isDebugEnabled()) {
|
|
|
log.debug("Finding route for path: " + path);
|
|
|
}
|
|
|
|
|
|
// This is called for the initialization done in getRoutesMap()
|
|
|
getRoutesMap();
|
|
|
|
|
|
if (log.isDebugEnabled()) {
|
|
|
log.debug("servletPath=" + this.dispatcherServletPath);
|
|
|
log.debug("zuulServletPath=" + this.zuulServletPath);
|
|
|
log.debug("RequestUtils.isDispatcherServletRequest()="
|
|
|
+ RequestUtils.isDispatcherServletRequest());
|
|
|
log.debug("RequestUtils.isZuulServletRequest()="
|
|
|
+ RequestUtils.isZuulServletRequest());
|
|
|
}
|
|
|
|
|
|
String adjustedPath = adjustPath(path);
|
|
|
|
|
|
ZuulProperties.ZuulRoute route = getZuulRoute(adjustedPath);
|
|
|
|
|
|
return getRoute(route, adjustedPath);
|
|
|
}
|
|
|
|
|
|
protected ZuulProperties.ZuulRoute getZuulRoute(String adjustedPath) {
|
|
|
if (!matchesIgnoredPatterns(adjustedPath)) {
|
|
|
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : getRoutesMap().entrySet()) {
|
|
|
String pattern = entry.getKey();
|
|
|
log.debug("Matching pattern:" + pattern);
|
|
|
if (this.pathMatcher.match(pattern, adjustedPath)) {
|
|
|
return entry.getValue();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
protected Route getRoute(ZuulProperties.ZuulRoute route, String path) {
|
|
|
if (route == null) {
|
|
|
return null;
|
|
|
}
|
|
|
if (log.isDebugEnabled()) {
|
|
|
log.debug("route matched=" + route);
|
|
|
}
|
|
|
String targetPath = path;
|
|
|
String prefix = this.properties.getPrefix();
|
|
|
if(prefix.endsWith("/")) {
|
|
|
prefix = prefix.substring(0, prefix.length() - 1);
|
|
|
}
|
|
|
if (path.startsWith(prefix + "/") && this.properties.isStripPrefix()) {
|
|
|
targetPath = path.substring(prefix.length());
|
|
|
}
|
|
|
if (route.isStripPrefix()) {
|
|
|
int index = route.getPath().indexOf("*") - 1;
|
|
|
if (index > 0) {
|
|
|
String routePrefix = route.getPath().substring(0, index);
|
|
|
targetPath = targetPath.replaceFirst(routePrefix, "");
|
|
|
prefix = prefix + routePrefix;
|
|
|
}
|
|
|
}
|
|
|
Boolean retryable = this.properties.getRetryable();
|
|
|
if (route.getRetryable() != null) {
|
|
|
retryable = route.getRetryable();
|
|
|
}
|
|
|
return new Route(route.getId(), targetPath, route.getLocation(), prefix,
|
|
|
retryable,
|
|
|
route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
|
|
|
route.isStripPrefix());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Calculate all the routes and set up a cache for the values. Subclasses can call
|
|
|
* this method if they need to implement {@link RefreshableRouteLocator}.
|
|
|
*/
|
|
|
protected void doRefresh() {
|
|
|
this.routes.set(locateRoutes());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Compute a map of path pattern to route. The default is just a static map from the
|
|
|
* {@link ZuulProperties}, but subclasses can add dynamic calculations.
|
|
|
*/
|
|
|
protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
|
|
|
LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
|
|
|
List<ZuulProperties.ZuulRoute> zuulRoutes = jdbcZuulRouteService.loadEnabledZuulRoutes();
|
|
|
zuulRoutes.forEach(item -> {
|
|
|
if (configPriority) {
|
|
|
if (properties.getRoutes().containsKey(item.getId())) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
String path = item.getPath();
|
|
|
if (!path.startsWith("/")) {
|
|
|
path = "/" + path;
|
|
|
}
|
|
|
if (StringUtils.hasText(this.properties.getPrefix())) {
|
|
|
path = this.properties.getPrefix() + path;
|
|
|
if (!path.startsWith("/")) {
|
|
|
path = "/" + path;
|
|
|
}
|
|
|
}
|
|
|
item.setPath(path);
|
|
|
this.properties.getRoutes().put(item.getId(), item);
|
|
|
});
|
|
|
for (ZuulProperties.ZuulRoute route : this.properties.getRoutes().values()) {
|
|
|
routesMap.put(route.getPath(), route);
|
|
|
}
|
|
|
return routesMap;
|
|
|
}
|
|
|
|
|
|
protected boolean matchesIgnoredPatterns(String path) {
|
|
|
for (String pattern : this.properties.getIgnoredPatterns()) {
|
|
|
log.debug("Matching ignored pattern:" + pattern);
|
|
|
if (this.pathMatcher.match(pattern, path)) {
|
|
|
log.debug("Path " + path + " matches ignored pattern " + pattern);
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
private String adjustPath(final String path) {
|
|
|
String adjustedPath = path;
|
|
|
|
|
|
if (RequestUtils.isDispatcherServletRequest()
|
|
|
&& StringUtils.hasText(this.dispatcherServletPath)) {
|
|
|
if (!this.dispatcherServletPath.equals("/")) {
|
|
|
adjustedPath = path.substring(this.dispatcherServletPath.length());
|
|
|
log.debug("Stripped dispatcherServletPath");
|
|
|
}
|
|
|
}
|
|
|
else if (RequestUtils.isZuulServletRequest()) {
|
|
|
if (StringUtils.hasText(this.zuulServletPath)
|
|
|
&& !this.zuulServletPath.equals("/")) {
|
|
|
adjustedPath = path.substring(this.zuulServletPath.length());
|
|
|
log.debug("Stripped zuulServletPath");
|
|
|
}
|
|
|
}
|
|
|
else {
|
|
|
// do nothing
|
|
|
}
|
|
|
|
|
|
log.debug("adjustedPath=" + adjustedPath);
|
|
|
return adjustedPath;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public int getOrder() {
|
|
|
return order;
|
|
|
}
|
|
|
|
|
|
public void setOrder(int order) {
|
|
|
this.order = order;
|
|
|
}
|
|
|
|
|
|
|
|
|
@Override
|
|
|
public void refresh() {
|
|
|
doRefresh();
|
|
|
}
|
|
|
|
|
|
public ZuulProperties getProperties() {
|
|
|
return properties;
|
|
|
}
|
|
|
|
|
|
}
|