Spring Cloud Edgware SR3 让Zuul支持形如 /xxx和/xxx/yyy 格式的路径配置

在包路径:org.springframework.cloud.netflix.zuul.filters 下,新建类SimpleRouteLocator,取代jar包中的类。内容如下:

  1 /*
  2  * Copyright 2013-2014 the original author or authors.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package org.springframework.cloud.netflix.zuul.filters;
 18 
 19 import java.util.ArrayList;
 20 import java.util.Collection;
 21 import java.util.LinkedHashMap;
 22 import java.util.List;
 23 import java.util.Map;
 24 import java.util.Map.Entry;
 25 import java.util.concurrent.atomic.AtomicReference;
 26 import org.apache.commons.logging.Log;
 27 import org.apache.commons.logging.LogFactory;
 28 import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
 29 import org.springframework.cloud.netflix.zuul.util.RequestUtils;
 30 import org.springframework.core.Ordered;
 31 import org.springframework.util.AntPathMatcher;
 32 import org.springframework.util.PathMatcher;
 33 import org.springframework.util.StringUtils;
 34 
 35 /**
 36  * Simple {@link RouteLocator} based on configuration data held in {@link ZuulProperties}.
 37  *
 38  * @author Dave Syer
 39  */
 40 public class SimpleRouteLocator implements RouteLocator, Ordered {
 41 
 42     private static final Log log = LogFactory.getLog(SimpleRouteLocator.class);
 43 
 44     private static final int DEFAULT_ORDER = 0;
 45 
 46     private ZuulProperties properties;
 47 
 48     private PathMatcher pathMatcher = new AntPathMatcher();
 49 
 50     private String dispatcherServletPath = "/";
 51     private String zuulServletPath;
 52 
 53     private AtomicReference<Map<String, ZuulRoute>> routes = new AtomicReference<>();
 54     private int order = DEFAULT_ORDER;
 55 
 56     public SimpleRouteLocator(String servletPath, ZuulProperties properties) {
 57         this.properties = properties;
 58         if (StringUtils.hasText(servletPath)) {
 59             this.dispatcherServletPath = servletPath;
 60         }
 61 
 62         this.zuulServletPath = properties.getServletPath();
 63     }
 64 
 65     @Override
 66     public List<Route> getRoutes() {
 67         List<Route> values = new ArrayList<>();
 68         for (Entry<String, ZuulRoute> entry : getRoutesMap().entrySet()) {
 69             ZuulRoute route = entry.getValue();
 70             String path = route.getPath();
 71             values.add(getRoute(route, path));
 72         }
 73         return values;
 74     }
 75 
 76     @Override
 77     public Collection<String> getIgnoredPaths() {
 78         return this.properties.getIgnoredPatterns();
 79     }
 80 
 81     @Override
 82     public Route getMatchingRoute(final String path) {
 83 
 84         return getSimpleMatchingRoute(path);
 85 
 86     }
 87 
 88     protected Map<String, ZuulRoute> getRoutesMap() {
 89         if (this.routes.get() == null) {
 90             this.routes.set(locateRoutes());
 91         }
 92         return this.routes.get();
 93     }
 94 
 95     protected Route getSimpleMatchingRoute(final String path) {
 96         if (log.isDebugEnabled()) {
 97             log.debug("Finding route for path: " + path);
 98         }
 99 
100         // This is called for the initialization done in getRoutesMap()
101         getRoutesMap();
102 
103         if (log.isDebugEnabled()) {
104             log.debug("servletPath=" + this.dispatcherServletPath);
105             log.debug("zuulServletPath=" + this.zuulServletPath);
106             log.debug("RequestUtils.isDispatcherServletRequest()="
107                     + RequestUtils.isDispatcherServletRequest());
108             log.debug("RequestUtils.isZuulServletRequest()="
109                     + RequestUtils.isZuulServletRequest());
110         }
111 
112         String adjustedPath = adjustPath(path);
113 
114         ZuulRoute route = getZuulRoute(adjustedPath);
115 
116         return getRoute(route, adjustedPath);
117     }
118 
119     protected ZuulRoute getZuulRoute(String adjustedPath) {
120         if (!matchesIgnoredPatterns(adjustedPath)) {
121             //2018年6月20日 马赛克:支持优先精确匹配-----start
122             Map m = (Map)this.routes.get();
123             ZuulRoute z = (ZuulRoute)m.get(adjustedPath);
124             if(z!=null){
125                 return z;
126             }
127             //2018年6月20日 马赛克:支持优先精确匹配-----end
128 
129             for (Entry<String, ZuulRoute> entry : getRoutesMap().entrySet()) {
130                 String pattern = entry.getKey();
131                 log.debug("Matching pattern:" + pattern);
132                 if (this.pathMatcher.match(pattern, adjustedPath)) {
133                     return entry.getValue();
134                 }
135             }
136         }
137         return null;
138     }
139 
140     protected Route getRoute(ZuulRoute route, String path) {
141         if (route == null) {
142             return null;
143         }
144         if (log.isDebugEnabled()) {
145             log.debug("route matched=" + route);
146         }
147         String targetPath = path;
148         String prefix = this.properties.getPrefix();
149         if(prefix.endsWith("/")) {
150             prefix = prefix.substring(0, prefix.length() - 1);
151         }
152         if (path.startsWith(prefix + "/") && this.properties.isStripPrefix()) {
153             targetPath = path.substring(prefix.length());
154         }
155 
156         if (route.isStripPrefix()) {
157             int index = route.getPath().indexOf("*") - 1;
158             if (index > 0) {
159                 String routePrefix = route.getPath().substring(0, index);
160                 targetPath = targetPath.replaceFirst(routePrefix, "");
161                 prefix = prefix + routePrefix;
162             }
163 
164             //2018年6月20日 马赛克:支持形如/xxx/bbb 而非/xxx/**的routes-----start
165             else{
166 
167                 String routePath = route.getPath();
168                 targetPath = routePath.substring(routePath.lastIndexOf("/"));
169                 prefix = prefix + routePath.substring(0,routePath.lastIndexOf("/"));
170             }
171             //2018年6月20日 马赛克:支持形如/xxx/bbb 而非/xxx/**的routes-----end
172         }
173         Boolean retryable = this.properties.getRetryable();
174         if (route.getRetryable() != null) {
175             retryable = route.getRetryable();
176         }
177         return new Route(route.getId(), targetPath, route.getLocation(), prefix,
178                 retryable,
179                 route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
180                 route.isStripPrefix());
181     }
182 
183     /**
184      * Calculate all the routes and set up a cache for the values. Subclasses can call
185      * this method if they need to implement {@link RefreshableRouteLocator}.
186      */
187     protected void doRefresh() {
188         this.routes.set(locateRoutes());
189     }
190 
191     /**
192      * Compute a map of path pattern to route. The default is just a static map from the
193      * {@link ZuulProperties}, but subclasses can add dynamic calculations.
194      */
195     protected Map<String, ZuulRoute> locateRoutes() {
196         LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>();
197         for (ZuulRoute route : this.properties.getRoutes().values()) {
198             routesMap.put(route.getPath(), route);
199         }
200         return routesMap;
201     }
202 
203     protected boolean matchesIgnoredPatterns(String path) {
204         for (String pattern : this.properties.getIgnoredPatterns()) {
205             log.debug("Matching ignored pattern:" + pattern);
206             if (this.pathMatcher.match(pattern, path)) {
207                 log.debug("Path " + path + " matches ignored pattern " + pattern);
208                 return true;
209             }
210         }
211         return false;
212     }
213 
214     private String adjustPath(final String path) {
215         String adjustedPath = path;
216 
217         if (RequestUtils.isDispatcherServletRequest()
218                 && StringUtils.hasText(this.dispatcherServletPath)) {
219             if (!this.dispatcherServletPath.equals("/")) {
220                 adjustedPath = path.substring(this.dispatcherServletPath.length());
221                 log.debug("Stripped dispatcherServletPath");
222             }
223         }
224         else if (RequestUtils.isZuulServletRequest()) {
225             if (StringUtils.hasText(this.zuulServletPath)
226                     && !this.zuulServletPath.equals("/")) {
227                 adjustedPath = path.substring(this.zuulServletPath.length());
228                 log.debug("Stripped zuulServletPath");
229             }
230         }
231         else {
232             // do nothing
233         }
234 
235         log.debug("adjustedPath=" + adjustedPath);
236         return adjustedPath;
237     }
238 
239     @Override
240     public int getOrder() {
241         return order;
242     }
243 
244     public void setOrder(int order) {
245         this.order = order;
246     }
247 
248 }

 

其中的164-171行,让zuul支持了如下配置:

zuul:
  routes:
    all:
      path: /vod2/two
      serviceId: all
    one:
      path: /vod1/one
      serviceId: one

 

通过/vod2/two路径,可以访问到 /all/two

注意,测试时不存在名为vod2和vod1的服务

 

posted @ 2018-06-20 16:22  剑握在手  阅读(878)  评论(0编辑  收藏  举报
返回顶部↑