1

我想从 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没有

4

1 回答 1

5

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

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 Expression Language (SpEL) 表达式,因此是单引号+等...

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

于 2019-01-09T16:39:21.610 回答