问题
I want to Migrating from zuul to spring cloud gateway, I don't want to change my config of previous app. I want to know how to handle with the url with "/api/ + 'serviceId'", route to lb://serviceId
the previous zuul config
zuul:
prefix: /api
there are lots of service regist to eureka ,i don't want to config a route for each one.
eg. the auto generated route by 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
}
what i wanted is
{
"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
}
how can i config my route to get what i want
And I also found the source code
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;
}
the "'/'+serviceId+'/**'" is there without a prefix
[2019-01-10] UPDATE I think @spencergibb's suggestion is a good solution, but I had new trouble with the (SpEL) I tried many ways:
args:
regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: '/${remaining}'
args:
regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
start failed
Origin: class path resource [application.properties]:23:70
Reason: Could not resolve placeholder 'remaining' in value "'${remaining}'"
when i use an escape "\" like
args:
regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: '/$\{remaining}'
it start success but i got an exception when running
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]
UPDATE 2
I found in the org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory
, there's a replacement to deal with "\"
...
@Override
public GatewayFilter apply(Config config) {
String replacement = config.replacement.replace("$\\", "$");
return (exchange, chain) -> {
...
when it comes to SpelParseException
there's none
回答1:
You can customize the automatic filters and predicates used via properties.
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}'"
Note the values (ie args.pattern
or args.regexp
) are all Spring Expression Language (SpEL) expressions, hence the single quotes and +
etc...
If different routes need to have different prefixes, you'd need to define each route in properties.
来源:https://stackoverflow.com/questions/54104281/how-to-remove-the-gobal-prefix-api-then-goto-the-lb-when-migrate-to-sp