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

 更新时间:2017年10月09日 10:29:13   作者:程序猿DD  
这篇文章主要介绍了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 服务,并且配置了如下路由规则:

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/** 路由才能实现上述需求。但是如果使用上面的配置方式,实际上是无法保证这样的路由优先顺序的。

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

@Override
public 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路径。

如果您有任何想法或问题需要讨论或交流,可进入交流区发表您的想法或问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • logstash将mysql数据同步到elasticsearch方法详解

    logstash将mysql数据同步到elasticsearch方法详解

    这篇文章主要为大家介绍了logstash将mysql数据同步到elasticsearch方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • SpringCloud集成和使用OpenFeign的教程指南

    SpringCloud集成和使用OpenFeign的教程指南

    在微服务架构中,服务间的通信是至关重要的,SpringCloud作为一个功能强大的微服务框架,为我们提供了多种服务间通信的方式,其中,OpenFeign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加简单,本文将详细介绍如何在SpringCloud项目中集成和使用OpenFeign
    2024-10-10
  • MyBatis3传递多个参数(Multiple Parameters)

    MyBatis3传递多个参数(Multiple Parameters)

    这篇文章主要介绍了MyBatis3传递多个参数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • SpringCloudGateway开发过程解析

    SpringCloudGateway开发过程解析

    这篇文章主要介绍了SpringCloudGateway开发过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • SpringBoot 中的异步处理机制详解

    SpringBoot 中的异步处理机制详解

    本文介绍了异步处理的基础配置、线程池的自定义以及常见应用场景,在实际应用中,异步处理可以有效提升应用的性能,改善用户体验,但同时也需要我们合理管理线程池,确保系统资源的高效利用,感兴趣的朋友跟随小编一起看看吧
    2025-01-01
  • java线程Thread.sleep()对比对象的wait示例解析

    java线程Thread.sleep()对比对象的wait示例解析

    这篇文章主要为大家介绍了java线程Thread.sleep()对比对象的wait示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Java定时器Timer使用方法详解

    Java定时器Timer使用方法详解

    这篇文章主要为大家详细介绍了Java定时器Timer的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • linux部署出现java文件操作报错:java.io.FileNotFoundException解决办法

    linux部署出现java文件操作报错:java.io.FileNotFoundException解决办法

    这篇文章主要g介绍了linux部署出现java文件操作报错:java.io.FileNotFoundException解决的相关资料,这个错误通常表示你的Spring Boot应用程序无法找到指定的文本文件,需要的朋友可以参考下
    2023-12-12
  • Spring Boot读取配置属性常用方法解析

    Spring Boot读取配置属性常用方法解析

    这篇文章主要介绍了Spring Boot读取配置属性常用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 如何自定义Jackson序列化 @JsonSerialize

    如何自定义Jackson序列化 @JsonSerialize

    这篇文章主要介绍了如何自定义Jackson序列化 @JsonSerialize,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论