路径匹配

不论是使用传统路由的配置方式还是服务路由的配置方式,我们都需要为每个路由规则定义匹配表达式,也就是上面所说的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服务,并且配置了如下路由规则:

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

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

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

zuul.routes.user-service-ext.path=/user-service/ext/**zuul.routes.user-service-ext.serviceId=user-service-ext

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

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

@Overridepublic Route getMatchingRoute(final String path) { ...   ZuulRoute route = null;  if (!matchesIgnoredPatterns(adjustedPath)) {      for (Entry<String, ZuulRoute> entry : this.routes.get().entrySet()) {           String pattern = entry.getKey();         log.debug("Matching pattern:" + pattern);          if (this.pathMatcher.match(pattern, adjustedPath)) {              route = entry.getValue();                break;            }     } } log.debug("route matched=" + route);  return getRoute(route, adjustedPath);}

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

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

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

zuul: routes: user-service-ext: path: /user-service/ext/** serviceId: user-service-ext user-service: path: /user-service/** serviceId: user-service

忽略表达式

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

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

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

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

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

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


SpringCloud实战小贴士:Zuul的路径匹配相关推荐

  1. SpringCloud实战小贴士:版本依赖关系

    2019独角兽企业重金招聘Python工程师标准>>> 去年在博客上连载了<Spring Cloud构建微服务架构>的系列博文,虽然这部分内容得到了不少关注者们的支持,但 ...

  2. Spring Cloud实战小贴士:版本依赖关系

    去年在博客上连载了<Spring Cloud构建微服务架构>的系列博文,虽然这部分内容得到了不少关注者们的支持,但是不得不说这些内容只是适用于Spring Cloud入门阶段对各个组件的初 ...

  3. Spring Cloud实战小贴士:Zuul处理Cookie和重定向

    由于我们在之前所有的入门教程中,对于HTTP请求都采用了简单的接口实现.而实际使用过程中,我们的HTTP请求要复杂的多,比如当我们将Spring Cloud Zuul作为API网关接入网站类应用时,往 ...

  4. Spring Cloud实战小贴士:Zuul统一异常处理(一)

    在上一篇<Spring Cloud源码分析(四)Zuul:核心过滤器>一文中,我们详细介绍了Spring Cloud Zuul中自己实现的一些核心过滤器,以及这些过滤器在请求生命周期中的不 ...

  5. Spring Cloud实战小贴士:Zuul统一异常处理(二)

    在前几天发布的<Spring Cloud实战小贴士:Zuul统一异常处理(一)>一文中,我们详细说明了当Zuul的过滤器中抛出异常时会发生客户端没有返回任何内容的问题以及针对这个问题的两种 ...

  6. Spring Cloud实战小贴士:Zuul统一异常处理(三)【Dalston版】

    本篇作为<Spring Cloud微服务实战>一书关于Spring Cloud Zuul网关在Dalston版本对异常处理的补充.没有看过本书的读书也不要紧,可以先阅读我之前的两篇博文:& ...

  7. Spring Cloud实战小贴士:Zuul的饥饿加载(eager-load)使用

    上一篇 我们介绍了如何使用Ribbon的 earger-load配置加速Spring Cloud中对服务接口的第一次调用.可是这样只是解决了内部服务间的调用,另外一个问题依然经常困扰我们,那就是网关到 ...

  8. Spring Cloud实战小贴士:随机端口

    太久没有更新,一时不知道该从哪儿开始,索性就从一个小技巧开始吧. 在之前的<Spring Cloud构建微服务架构>系列博文中,我们经常会需要启动多个实例的情况来测试注册中心.配置中心等基 ...

  9. Spring Cloud实战小贴士:健康检查

    今天在博客的交流区收到一条不错的问题,拿出来给大家分享一下.具体问题如下: 因为项目里面用到了redis集群,但并不是用spring boot的配置方式,启动后项目健康检查老是检查redis的时候状态 ...

最新文章

  1. Java SE 6之GUI:让界面更加绚丽(上)
  2. visual studio编译错误集(转)
  3. 2018-2019-1 20165231 实验四 外设驱动程序设计
  4. linux mysql general_利用mysql general log 写shell 可行性简要分析
  5. 图像超分辨率也能改善天气预报?没错!
  6. 鼠标和按键在android 上的识别和区别
  7. java.lang.InstantiationException: DWR can't find a spring config. See the logs for solutions
  8. 深圳的90后,是如何渡过他们的周末的?
  9. 国产代码审计工具Pinpoint介绍
  10. 防病毒服务器维护记录表,机房巡检记录表.doc
  11. Windows Server 2016忘记密码破解方法
  12. 3个方法教你怎么避免拼多多比价订单
  13. 中国软件行进销存管理系统 免费
  14. AppSpider:Xposed+JustTrustMe关闭SSL证书验证
  15. 统计学习方法总结、应用对比
  16. C语言 键盘编码 及 用法
  17. 2021年美亚杯资格赛解析
  18. Unity3D游戏开发之在uGUI中使用不规则精灵制作按钮
  19. 神经网络中的反向传播
  20. ​Excel如何转换成Word文档?教你如何实现转换

热门文章

  1. Android sqlite数据库操作通用框架AHibernate(二)源码-用于交流
  2. C语言指针:从底层原理到花式技巧,用图文和代码帮你讲解透彻
  3. Linux 内核完成接口
  4. I2C和SPI注定要打一架
  5. esp32 coredump分析
  6. container_of宏
  7. 人体反应测试仪 c语言,人体反应速度测试仪毕业设计说明
  8. OpenCV_08 边缘检测:Sobel检测算子+Laplacian算子+Canny边缘检测
  9. PyTorch的nn.Linear()详解
  10. Spring.io本地服务器解决超时问题