Spring Cloud Gatewayでは、uriとpathが同じ時に経路が削除され、404に戻る.
3863 ワード
現象
ルートの設定は、パスを要求する.http://ip:port/gateway/hi ジャンプを期待しています.lb://Gateway/hi 実際にジャンプします.lb://Gateway/hi パスを要求できなくなり、404を返します.
原因分析
Spring 5.0はreactive(反応式)のプログラミングコンセプトを使用し始め、SCGはデフォルトでは登録センターに登録されたサービスを主導してデフォルトのルートルールを作成し、優先とカスタムルールを切って、カスタムルールが無効になります.
ソースは以下の通りです
デフォルトではeureka上のすべてのサービスに対してpath=/service_を作成します.id/*のルートマッチング RewritePathGateway FilterFactory工場で生成されたフィルタは、経路を入れ替えます.
反応式をオフにしてルートを作成します.
ルートの設定
- id: r_invitation
uri: lb://Gateway #eureka Gateway
predicates:
- Path=/gateway/**
原因分析
Spring 5.0はreactive(反応式)のプログラミングコンセプトを使用し始め、SCGはデフォルトでは登録センターに登録されたサービスを主導してデフォルトのルートルールを作成し、優先とカスタムルールを切って、カスタムルールが無効になります.
ソースは以下の通りです
デフォルトではeureka上のすべてのサービスに対してpath=/service_を作成します.id/*のルートマッチング
public class GatewayDiscoveryClientAutoConfiguration {
public static List initPredicates() {
ArrayList 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;
}
public static List initFilters() {
ArrayList definitions = new ArrayList<>();
// add a filter that removes /serviceId by default
FilterDefinition filter = new FilterDefinition();
filter.setName(normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
String regex = "'/' + serviceId + '/(?.*)'";
String replacement = "'/${remaining}'";
filter.addArg(REGEXP_KEY, regex);
filter.addArg(REPLACEMENT_KEY, replacement);
definitions.add(filter);
return definitions;
}
@Bean
public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
properties.setPredicates(initPredicates());
properties.setFilters(initFilters());
return properties;
}
/**
* @deprecated In favor of the native reactive service discovery capability.
* , false
*/
@Configuration(proxyBeanMethods = false)
@Deprecated
@ConditionalOnProperty(value = "spring.cloud.discovery.reactive.enabled",
havingValue = "false")
public static class BlockingDiscoveryClientRouteDefinitionLocatorConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}
}
}
package org.springframework.cloud.gateway.filter.factory;
...
public class RewritePathGatewayFilterFactory
extends AbstractGatewayFilterFactory {
...
return new GatewayFilter() {
@Override
public Mono filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
ServerHttpRequest req = exchange.getRequest();
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(GATEWAY_REQUEST_URL_ATTR, request.getURI());
return chain.filter(exchange.mutate().request(request).build());
}
...
}
解決策反応式をオフにしてルートを作成します.
spring.cloud.discovery.reactive.enabled = false
注:この機能は5.2バージョンで利用できます.github上の5.3バージョンの原発発見を確認したら、この構成はすでに削除されました.例えば5.3を使うにはさらに分析が必要です.