SpringCloud实战小贴士:Zuul的路径匹配

简介:

路径匹配

不论是使用传统路由的配置方式还是服务路由的配置方式,我们都需要为每个路由规则定义匹配表达式,也就是上面所说的path参数。在Zuul中,路由匹配的路径表达式采用了Ant风格定义。

Ant风格的路径表达式使用起来非常简单,它一共有下面这三种通配符:

通配符说明

我们可以通过下表的示例来进一步理解这三个通配符的含义并参考着来使用:

URL路径说明

/user-service/?它可以匹配/user-service/之后拼接一个任务字符的路径,比如:/user-service/a、/user-service/b、/user-service/c

/user-service/*它可以匹配/user-service/之后拼接任意字符的路径,比如:/user-service/a、/user-service/aaa、/user-service/bbb。但是它无法匹配/user-service/a/b

/user-service/**它可以匹配/user-service/*包含的内容之外,还可以匹配形如/user-service/a/b的多级目录路径

另外,当我们使用通配符的时候,经常会碰到这样的问题:一个URL路径可能会被多个不同路由的表达式匹配上。比如:有这样的一个场景,我们在系统建设的一开始实现了user-service服务,并且配置了如下路由规则:

 
 
  1. zuul.routes.user-service.path=/user-service/** 
  2. zuul.routes.user-service.serviceId=user-service 

但是随着版本的迭代,我们对user-service服务做了一些功能拆分,将原属于user-service服务的某些功能拆分到了另外一个全新的服务user-service-ext中去,而这些拆分的外部调用URL路径希望能够符合规则/user-service/ext/**,这个时候我们需要就在配置文件中增加一个路由规则,完整配置如下:

 
 
  1. zuul.routes.user-service.path=/user-service/** 
  2. zuul.routes.user-service.serviceId=user-service 
  3.  
  4. zuul.routes.user-service-ext.path=/user-service/ext/** 
  5. zuul.routes.user-service-ext.serviceId=user-service-ext 

这个时候,调用user-service-ext服务的URL路径实际上会同时被/user-service/**和/user-service/ext/**两个表达式所匹配。在逻辑上,API网关服务需要优先选择/user-service/ext/**路由,然后再匹配/user-service/**路由才能实现上述需求。但是如果使用上面的配置方式,实际上是无法保证这样的路由优先顺序的。

从下面的路由匹配算法中,我们可以看到它在使用路由规则匹配请求路径的时候是通过线性遍历的方式,在请求路径获取到第一个匹配的路由规则之后就会返回并结束匹配过程。所以当存在多个匹配的路由规则时,匹配结果完全取决于路由规则的保存顺序。

 
 
  1. @Override 
  2. public Route getMatchingRoute(final String path) { 
  3.     ... 
  4.     ZuulRoute route = null
  5.     if (!matchesIgnoredPatterns(adjustedPath)) { 
  6.         for (Entry<String, ZuulRoute> entry : this.routes.get().entrySet()) { 
  7.             String pattern = entry.getKey(); 
  8.             log.debug("Matching pattern:" + pattern); 
  9.             if (this.pathMatcher.match(pattern, adjustedPath)) { 
  10.                 route = entry.getValue(); 
  11.                 break; 
  12.             } 
  13.         } 
  14.     } 
  15.     log.debug("route matched=" + route); 
  16.     return getRoute(route, adjustedPath); 

下面所示代码是基础的路由规则加载算法,我们可以看到这些路由规则是通过LinkedHashMap保存的,也就是说路由规则的保存是有序的,而内容的加载是通过遍历配置文件中路由规则依次加入的,所以导致问题的根本原因是对配置文件中内容的读取。

 
 
  1. protected Map<String, ZuulRoute> locateRoutes() { 
  2.     LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>(); 
  3.     for (ZuulRoute route : this.properties.getRoutes().values()) { 
  4.         routesMap.put(route.getPath(), route); 
  5.     } 
  6.     return routesMap; 

由于properties的配置内容无法保证有序,所以当出现这种情况的时候,为了保证路由的优先顺序,我们需要使用YAML文件来配置,以实现有序的路由规则,比如使用下面的定义:

 
 
  1. zuul: 
  2.   routes: 
  3.     user-service-ext: 
  4.       path: /user-service/ext/** 
  5.       serviceId: user-service-ext 
  6.     user-service: 
  7.       path: /user-service/** 
  8.       serviceId: user-service 

忽略表达式

通过path参数定义的Ant表达式已经能够完成API网关上的路由规则配置功能,但是为了更细粒度和更为灵活的配置路由规则,Zuul还提供了一个忽略表达式参数:zuul.ignored-patterns。该参数可以用来设置不希望被API网关进行路由的URL表达式。

比如,以快速入门中的示例为基础,如果我们不希望/hello接口被路由,那么我们可以这样设置:

 
 
  1. zuul.ignored-patterns=/**/hello/** 
  2. zuul.routes.api-a.path=/api-a/** 
  3. zuul.routes.api-a.serviceId=hello-service 

然后,可以尝试通过网关来访问hello-service的/hello接口:http://localhost:5555/api-a/hello。虽然该访问路径的完全符合path参数定义的/api-a/**规则,但是由于该路径符合zuul.ignored-patterns参数定义的规则,所以不会被正确路由。同时,我们在控制台或日志中还能看到没有匹配路由的输出信息:

 
 
  1. o.s.c.n.z.f.pre.PreDecorationFilter      : No route found for uri: /api-a/hello 

另外,该参数在使用时还需要注意它的范围并不是对某个路由,而是对所有路由的。所以在设置的时候需要全面的考虑URL规则,防止忽略了不该被忽略的URL路径。 


原文发布时间为:2017-10-18

本文作者:翟永超

本文来自云栖社区合作伙伴“51CTO”,了解相关信息可以关注。

相关文章
|
4月前
|
Java
SpringBoot 映射路径中 匹配正则表达式
SpringBoot 映射路径中 匹配正则表达式
62 0
|
10月前
|
负载均衡 Java 微服务
十八.SpringCloud源码剖析-Zuul的自动配置和核心Filter详解
在上一章节我们大致了解了Zuul的Filter的执行流程和核心的Filter,这一章节我们消息分析一下Zuul的自动配置,以及每个Filter的实现细节,这需要你有一定的耐心
|
10月前
|
负载均衡 Java 微服务
SpringCloud源码剖析-Zuul的自动配置和核心Filter详解
EnableZuulProxy的注释告诉我们,这里设设置Zuul服务器端点,和安装了一些反向代理过滤器,通过这些过滤器它可以转发请求到后端服务器,可以通过配置或通过DiscoveryClient手动注册后端服务(服务发现)
154 0
|
Java
Springboot+AngularJS+Spring-data-Solr:搜索内容匹配高亮显示
Springboot+AngularJS+Spring-data-Solr:搜索内容匹配高亮显示
102 0
Springboot+AngularJS+Spring-data-Solr:搜索内容匹配高亮显示
|
JSON Java 数据格式
SpringBoot2.x系列教程17--SpringBoot中对URL路径规则的特殊匹配实现方案
前言 在前面的章节中,壹哥 带大家对JSON进行了序列化和反序列化的特殊处理,但是我们开发时,不仅仅JSON需要特殊处理,有时候就连我们的URL接口地址中也有需要特殊处理的地方。 比如,在一个URL中,“.” 字符一般是作为分隔符来定义格式的,例如/projects/spring-boot.json中的 “点” ,那么如果在URL带有这个 ”.“,我们要不要做特殊的处理呢? 另外有的人在访问URL时,可能会在尾部带有一个”/“,如果我们想识别URL路径尾部的斜杠,如“/home/”中的第2个 “/”,该怎么办? 这些都是一些比较特殊的需求,那么我们要不要处理呢?接下来 壹哥 就教各位把U
1057 0
|
前端开发 Java Spring
Spring RequestMapping检测路径匹配核心类AntPathMatcher
Spring RequestMapping检测路径匹配核心类AntPathMatcher
|
前端开发 Java API
SpringBoot请求后缀不匹配也能访问的问题
SpringBoot请求后缀不匹配也能访问的问题
SpringCloud - Zuul(三)(上)
SpringCloud - Zuul(三)(上)
118 0
SpringCloud - Zuul(三)(上)
|
开发工具 git
SpringCloud - Zuul(三)(中)
SpringCloud - Zuul(三)(中)
87 0
SpringCloud - Zuul(三)(下)
SpringCloud - Zuul(三)(下)
131 0