zuul路由配置路径前缀问题

zuul路由配置路径前缀问题

背景

我们项目组刚使用spring cloud项目不久,项目运行了几个月也没有使用zuul作网关,之前是使用nginx配置不同路径规则进行不能服务端口的转发。nginx配置如下:

location ^~ /user/ {
    proxy_pass http://xx.xx.xx.xx:xxxx;
}
location ^~ /product/ {
    proxy_pass http://xx.xx.xx.xx:xxxx;
}
location ^~ /cert/ {
    proxy_pass http://xx.xx.xx.xx:xxxx;
}
...

路径转发后对原始路径没有做任何修改,因此服务中Rest接口定义路径的时候会保留 /user/、/product/、/cert/这样的前缀。如:

@RestController
@RequestMapping("/user/")   // 保留服务模块定位前缀
public class XXXController {
    // code
}

为什么要使用zuul?

zuul作为网关除了做路由转发之外,它提供的过滤器可以做权限控制、限流、API监控等功能,因此引入zuul对项目的长期维护来说是有好处的。

出现问题

添加了一个gateway-zuul工程,在application.yml中添加了如下路由配置:

spring:
  application:
    name: gateway-zuul

server:
  port: 8888

zuul:
  routes:
    api-user:
      path: /user/**
      service-id: xxx-USER-SERVICE

启动工程, 访问接口:http://localhost:8888/user/xxx/xxx, 返回404。

排查问题

  1. 首先调试代码排查,发现路由过程是按照下面类的流程走的

    ZuulServletFilter
    ->
    ZuulRunner
    -> route()
    FilterProcessor
    -> runFilters('route')
    ZuulFilter
    -> run()
    RibbonRoutingFilter
    
    

    发现RibbonRoutingFilter执行中RequestContext中的RequestURI的值已经是/xxx/xxx了

    前缀/user不见了

  2. 猜测在preRouting 阶段应该是做了path截断了.

    发现pre截断有一个Filter类叫 PreDecorationFilter,

    它的run方法是这样的:

     @Override
     public Object run() {
         RequestContext ctx = RequestContext.getCurrentContext();
         final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());
         Route route = this.routeLocator.getMatchingRoute(requestURI);
         if (route != null) {
             // ....
         }
         // ...   
        }
    

    在解析requestURI获取组装对象Route的时候发现 route中的path前缀被截取了,继续深入
    发现了SimpleRouteLocator这个类中获取路由对象的方法:

    
     protected Route getRoute(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 (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前缀的地方是

         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;
             }
         }
    

    发现截取条件表达式route.isStripPrefix()的值是在ZuulProperties类中获取,而ZuulProperties类的数据来源就是application.yml中的zuul配置。

    问题定位。

解决问题

设置ZuulProperties类中的stripPrefix属性,在application.yml相应route配置的地方加上配置属性strip-prefix:fase,如下:

zuul:
  routes:
    api-user:
      path: /user/**
      service-id: CASH-USER-CENTER-SERVICE
      strip-prefix: false

重启服务,发现路径不再被截断,问题解决!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值