美文网首页开源框架-SpringCloud系列
Spring Cloud Gateway -- 关于Path的配

Spring Cloud Gateway -- 关于Path的配

作者: qiyinger | 来源:发表于2019-01-30 11:29 被阅读0次

    直接用官方文档的例子好了。。假设网关的地址是localhost:8080

    在符合时间范围内才匹配

    spring:
      cloud:
        gateway:
          routes:
          - id: before_route
            uri: http://localhost:8001
            predicates:
          # 在某个时间之前的请求才会被转发到 http://localhost:8001,
            - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
          # 在某个时间之后的请求才会被转发
          # - After=2017-01-20T17:42:47.789-07:00[America/Denver]
          # 在某个时间段之间的才会被转发
          # - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
    

    按表单名进行匹配

    spring:
      cloud:
        gateway:
          routes:
          - id: cookie_route
            uri: http://example.org
            predicates:
            # 名为chocolate的表单或者满足正则ch.p的表单才会被匹配到进行请求转发
            - Cookie=chocolate, ch.p
    

    按请求头匹配

    spring:
      cloud:
        gateway:
          routes:
          - id: header_route
            uri: http://example.org
            predicates:
            # 携带参数X-Request-Id或者满足\d+的请求头才会匹配
            - Header=X-Request-Id, \d+
    

    按Host主机名匹配

    • 访问特定的主机名才能匹配,若网关的地址是localhost:8080, 主机名是qiying.com:8080(80端口被占了),那么只有访问http:qiying.com:8080/app/test 请求才会转发到localhost:8001/app/test。
    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Host=qiying.com:8080
    

    若直接访问localhost:8080/test 则网关会匹配失败


    image.png

    按请求方法匹配

    spring:
      cloud:
        gateway:
          routes:
          - id: method_route
            uri: http://example.org
            predicates:
            # 只有GET方法才会匹配
            - Method=GET
    

    按请求路径匹配

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/app/{path}
          # - Path=/app/test
    

    结合一些filter更好用哦

    PrefixPath Filter 在请求路径前加上自定义的路径

    假如应用访问地址是localhost:8001/app, 接口地址是/test,这里设置了prefixPath为/app, 那么当你访问localhost:8080/test, 网关在帮你转发请求之前,会在/test 前加上/app,转发时的请求就变成了localhost:8001/app/test。

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/{path}
            filters:
            - PrefixPath=/app
    

    RewritePath Filter 重写请求路径

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/{path}
            filters:
            # 访问localhost:8080/test, 请求会转发到localhost:8001/app/test
            - RewritePath=/test, /app/test
    

    这个filter比较灵活的就是可以进行正则匹配替换,如下的例子就是当请求localhost:8080/test时,匹配所有以/开头的路径,然后在前面加上/app,所以现在请求变成了localhost:8080/app/test。然后转发时的url变成了localhost:8001/app/test 。在测试的时候,这个filter是没办法使用模板进行匹配的。可能是因为它是用的正则进行匹配替换,所以没办法使用模板吧

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/test
            filters:
            - RewritePath=(?<oldPath>^/), /app$\{oldPath}
    

    值得注意的是在yml文档中 $ 要写成 $\ 。替换路径是使用的是String.replaceAll()方法,这个方法和replace()不同,是根据正则进行替换的。具体的替换规则感兴趣的话可以去了解一下Pattern。
    https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

    public GatewayFilter apply(RewritePathGatewayFilterFactory.Config config) {
        // 可以看到在RewritePathGatewayFilterFactory中  $\ 会被替换回 $ 
        String replacement = config.replacement.replace("$\\", "$");
        return (exchange, chain) -> {
          ServerHttpRequest req = exchange.getRequest();
          ServerWebExchangeUtils.addOriginalRequestUrl(exchange, req.getURI());
          String path = req.getURI().getRawPath();
          String newPath = path.replaceAll(config.regexp, replacement);
          ServerHttpRequest request = req.mutate().path(newPath).build();
          exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, request.getURI());
          return chain.filter(exchange.mutate().request(request).build());
        };
      }
    

    SetPath Filter 通过模板设置路径

    这个filter的使用方式比较简单。就是匹配到满足/a开头的路径后重新设置路径为以/app开头。

    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/a/{path}
            filters:
            - SetPath=/app/{path}
    

    看到这里,大家应该大概了解了模板{...}的具体用法了吧。模板里面的变量可通过ServerWebExchange.getAttributes()获得。具体的请参看官方文档。

    最后的最后,因为好奇三种关于path的filter能不能一起用,所以做了个测试。

    • 首先先看PrefixPath 和 RewritePath。
      通过debuge可以发现,先进入PrefixPathGatewayFilterFactory的apply()方法,然后执行后面的filter链。然后进入RewritePathGatewayFilterFactory的apply()方法,再执行后面的filter。然后执行PrefixPathGatewayFilterFactory#apply()的return里的方法,开始替换路径,最后再执行RewritePathGatewayFilterFactory#apply()的return方法。所以先进行的是前缀替换,在进行正则替换。配置如下,请求localhost:8080/test 最终 会变成localhost:8001/api/app/test
    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/{path}
            filters:
            - PrefixPath=/app
            - RewritePath=(?<oldPath>^/), /api$\{oldPath}
    
    • 然后三种filter一起测试。。事实证明没办法正常工作。虽然最先进入的filter是SetPathGatewayFilterFactory。
      在理想情况,如果按照filter的执行顺序,如下配置下的url最终会变成localhost:8001/api/app/a/test。
    spring:
      cloud:
        gateway:
          routes:
          - id: host_route
            uri: http://localhost:8001
            predicates:
            - Path=/{path}
            filters:
            - PrefixPath=/app
            - RewritePath=(?<oldPath>^/), /api$\{oldPath}
            - SetPath=/a/{path}
    

    但是!!我们来看看SetPathGatewayFilterFactory的apply方法。一进入这个方法,{path}(/test)就被记录下来了。当另外两个filter的return方法执行完了之后,才会执行这个方法的return 方法。最后路径就会被替换为/a/test。所以SetPathFilter和另外两个Filter是没办法同时生效滴!

     public GatewayFilter apply(SetPathGatewayFilterFactory.Config config) {
        UriTemplate uriTemplate = new UriTemplate(config.template);
        return (exchange, chain) -> {
          PathMatchInfo variables = (PathMatchInfo)exchange.getAttribute(ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
          ServerHttpRequest req = exchange.getRequest();
          ServerWebExchangeUtils.addOriginalRequestUrl(exchange, req.getURI());
          Map uriVariables;
          if (variables != null) {
            uriVariables = variables.getUriVariables();
          } else {
            uriVariables = Collections.emptyMap();
          }
    
          URI uri = uriTemplate.expand(uriVariables);
          String newPath = uri.getRawPath();
          exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, uri);
          ServerHttpRequest request = req.mutate().path(newPath).build();
          return chain.filter(exchange.mutate().request(request).build());
        };
      }
    

    最后的最后的最后。。来打脸了。这个filter的执行顺序和配置定义的顺序是有关系的。。

     filters:
            - SetPath=/a/{path}
            - RewritePath=(?<oldPath>^/), /api$\{oldPath}
            - PrefixPath=/app
    

    按照这个顺序的话,先执行的就是将 /test替换为 /a/test,然后替换为/api/a/test,最后替换为/app/api/test。。
    由此得出的结论是只要SetPath这个filter在其他两个filter之前执行的话还是不冲突的。。

    相关文章

      网友评论

        本文标题:Spring Cloud Gateway -- 关于Path的配

        本文链接:https://www.haomeiwen.com/subject/kfixsqtx.html