从 zuul 迁移到 spring 云网关时如何 "remove the gobal prefix('/api') then goto the lb:// "

How to "remove the gobal prefix('/api') then goto the lb:// " when migrate to spring cloud gateway from zuul

我想从 zuul 迁移到 spring 云网关,我不想更改以前应用程序的配置。我想知道如何使用“/api/ + 'serviceId'”处理 url,路由到 lb://serviceId

之前的zuul配置

zuul: 
  prefix: /api

eureka 有很多服务注册,我不想为每个注册一个路由。

例如。 org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator

自动生成的路线
{
"route_id": "CompositeDiscoveryClient_APIGATEWAY",
"route_definition": {
  "id": "CompositeDiscoveryClient_APIGATEWAY",
  "predicates": [
    {
      "name": "Path",
      "args": {
        "pattern": "/apigateway/**"
      }
    }
  ],
  "filters": [
    {
      "name": "RewritePath",
      "args": {
        "regexp": "/apigateway/(?<remaining>.*)",
        "replacement": "/${remaining}"
      }
    }
  ],
  "uri": "lb://APIGATEWAY",
  "order": 0
}

我想要的是

 {
"route_id": "CompositeDiscoveryClient_APIGATEWAY",
"route_definition": {
  "id": "CompositeDiscoveryClient_APIGATEWAY",
  "predicates": [
    {
      "name": "Path",
      "args": {
        "pattern": "/api/apigateway/**"
      }
    }
  ],
  "filters": [
    {
      "name": "RewritePath",
      "args": {
        "regexp": "/api/apigateway/(?<remaining>.*)",
        "replacement": "/${remaining}"
      }
    }
  ],
  "uri": "lb://APIGATEWAY",
  "order": 0
}

我如何配置我的路线以获得我想要的

而且我还找到了源码

    public static List<PredicateDefinition> initPredicates() {
    ArrayList<PredicateDefinition> definitions = new ArrayList<>();
    // TODO: add a predicate that matches the url at /serviceId?

    // add a predicate that matches the url at /serviceId/**
    PredicateDefinition predicate = new PredicateDefinition();
    predicate.setName(normalizeRoutePredicateName(PathRoutePredicateFactory.class));
    predicate.addArg(PATTERN_KEY, "'/'+serviceId+'/**'");
    definitions.add(predicate);
    return definitions;
}

“'/'+serviceId+'/**'”没有前缀

[2019-01-10]更新 我认为@spencergibb 的建议是一个很好的解决方案,但我在 (SpEL) 方面遇到了新的麻烦 我尝试了很多方法:

args:
  regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
  replacement: '/${remaining}'
args:
  regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
  replacement: "'/${remaining}'"

启动失败

Origin: class path resource [application.properties]:23:70
Reason: Could not resolve placeholder 'remaining' in value "'${remaining}'"

当我使用像

这样的转义符“\”时
args:
  regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
  replacement: '/$\{remaining}'

它开始成功但我在 运行

时遇到异常
org.springframework.expression.spel.SpelParseException: Expression [/$\{remaining}] @2: EL1065E: unexpected escape character.
at org.springframework.expression.spel.standard.Tokenizer.raiseParseException(Tokenizer.java:590) ~[spring-expression-5.0.5.RELEASE.jar:5.0.5.RELEASE]
at org.springframework.expression.spel.standard.Tokenizer.process(Tokenizer.java:265) ~[spring-expression-5.0.5.RELEASE.jar:5.0.5.RELEASE]



更新 2

我在org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory中找到了一个替换来处理“\”

...    
@Override
        public GatewayFilter apply(Config config) {
            String replacement = config.replacement.replace("$\", "$");
            return (exchange, chain) -> {
...

当谈到 SpelParseException 时,有 none

您可以自定义通过属性使用的自动过滤器和谓词。

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          predicates:
            - name: Path
              args:
                pattern: "'/api/'+serviceId.toLowerCase()+'/**'"
          filters:
            - name: RewritePath
              args:
                regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
                replacement: "'/${remaining}'"

注意值(即 args.patternargs.regexp)都是 Spring 表达式语言 (SpEL) 表达式,因此单引号和 + 等...

如果不同的路由需要有不同的前缀,您需要在属性中定义每个路由。