Spring Cloud Gateway - 代理/转发 URL 的整个子部分
Posted
技术标签:
【中文标题】Spring Cloud Gateway - 代理/转发 URL 的整个子部分【英文标题】:Spring Cloud Gateway - Proxy/Forward the entire sub part of URL 【发布时间】:2018-07-29 15:06:35 【问题描述】:我正在使用Spring Cloud Gateway 2.0.0.M6 测试一个简单的网关。我只想将一个 URL 转发到另一个带有 ** 正则表达式的 URL
示例 1:/integration/sbl/foo/bar => localhost:4178/a-integration/sbl/foo/bar
示例 2:/integration/sbl/baz/bad => localhost:4178/a-integration/sbl/baz/bad
到目前为止,我已经写了以下内容,但它只转发给http://localhost:4178/a-integration/
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder)
String test = "http://localhost:4178/a-integration/";
return builder.routes()
.route("integration-test",
r -> r.path("/integration/sbl/**")
.uri(test)
)
.build();
如何修复上述代码以启用此行为?
编辑
我根据以下回复尝试了以下操作
String samtykke = "http://localhost:4178/";
return builder.routes()
.route("samtykke", r -> r
.path("/gb-integration/sbl/**")
.filters(f -> f.rewritePath("/gb-integration/sbl/(?<segment>.*)", "/gb-samtykke-integration/$segment"))
.uri(samtykke))
.build();
我尝试了 GET http://localhost:4177/gb-integration/sbl/api/sbl/income/ 并期望返回 http://localhost:4178/gb-samtykke-integration/api/sbl/income/,但它不起作用。
输出显示:
2018-02-23 09:46:35.197 TRACE 6364 --- [ctor-http-nio-2] o.s.c.g.h.p.RoutePredicateFactory : Pattern "/gb-integration/sbl/**" matches against value "[path='/gb-integration/sbl/api/sbl/income/']"
2018-02-23 09:46:35.198 DEBUG 6364 --- [ctor-http-nio-2] o.s.c.g.h.RoutePredicateHandlerMapping : Route matched: samtykke
2018-02-23 09:46:35.198 DEBUG 6364 --- [ctor-http-nio-2] o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: GET http://localhost:4177/gb-integration/sbl/api/sbl/income/] to Routeid='samtykke', uri=http://localhost:4178/, order=0, predicate=org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$245/1803714790@1d0042df, gatewayFilters=[OrderedGatewayFilterdelegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$247/485237151@77da026a, order=0]
2018-02-23 09:46:35.200 DEBUG 6364 --- [ctor-http-nio-2] o.s.c.g.handler.FilteringWebHandler : Sorted gatewayFilterFactories: [OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@5c534b5b, order=-1, OrderedGatewayFilterdelegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda$247/485237151@77da026a, order=0, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@396639b, order=10000, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@a18649a, order=2147483647, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@2b22a1cc, order=2147483647, OrderedGatewayFilterdelegate=GatewayFilterAdapterdelegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@62573c86, order=2147483647]
2018-02-23 09:46:35.232 TRACE 6364 --- [ctor-http-nio-2] o.s.c.g.filter.RouteToRequestUrlFilter : RouteToRequestUrlFilter start
2018-02-23 09:46:35.314 TRACE 6364 --- [ctor-http-nio-1] o.s.c.g.filter.NettyWriteResponseFilter : NettyWriteResponseFilter start
【问题讨论】:
使用重写路径设置路径过滤器 对不起,我不明白你的意思。你能用代码提供答案吗? 【参考方案1】:您可以在路径过滤器中使用 rewritePath 功能,如此处找到的文档所指定:
https://cloud.spring.io/spring-cloud-gateway/reference/html/#rewritepath-gatewayfilter-factory
相关部分:
5.12 RewritePath GatewayFilter 工厂
RewritePath GatewayFilter Factory 采用路径正则表达式参数 和一个替换参数。这使用 Java 正则表达式 重写请求路径的灵活方式。
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: http://example.org
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\segment
对于 /foo/bar 的请求路径,这会将路径设置为 /bar 之前 发出下游请求。注意 $\ 替换为 $ 因为 YAML 规范。
在你的例子中,这看起来像:
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder)
String test = "http://localhost:4178";
return builder.routes()
.route("integration-test", r -> r
.path("/integration/sbl/**")
.filters(f->f.rewritePath("/integration/(?<segment>.*)","/a-integration/$segment"))
.uri(test)
)
.build();
【讨论】:
嗨。感谢您的回复。我试过这个,但它并不完全奏效。我得到以下输出: Pattern "/gb-integration/sbl/**" matches against value "[path='/gb-integration/sbl/api/sbl/income/']" RoutePredicateHandlerMapping : Route matched: samtykke o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: GET http://localhost:4177/gb-integration/sbl/api/sbl/income/] to Routeid='samtykke', uri=http://localhost:4178/, order=0
注意我稍微改变了路径。输出显示它匹配,但从调试语句看来它只重定向到localhost:4178 而不是我想要的localhost:4178/api/sbl/income。我尝试在 localhost:4177/gb-integration/sbl/api/sbl/income 上执行 GET,但我什至没有得到 localhost:4178 回来,这很奇怪,因为它从输出中看起来像是匹配了
我编辑了我的问题并在问题中添加了评论以更清楚
如果您从 URI 中删除尾部斜杠,它将起作用。
我不确定为什么云网关不只是忽略那个斜线......添加斜线会产生意外行为,我会创建一个问题【参考方案2】:
我们在这里遇到了类似的问题,虽然我同意 Boyen 的回应,但指出 “uri”参数忽略 URI 的“路径”组件可能会很有用。这在文档中并不清楚(或者至少我还没有找到),所以我希望它可以帮助其他人。
假设您要将在 /foo 收到的所有请求重定向到 http://example.org/bar
例如:/foo/x/y/z --> http://example.org/bar/x/y/z
例如,这按预期工作:
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: http://example.org
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /bar/$\segment
虽然这不能按预期工作(它忽略 /bar):
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: http://example.org/bar
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\segment
【讨论】:
【参考方案3】:请在下面找到完整设置的两种配置。两种方法产生相同的结果。
设置:
网关正在http://localhost:8090
上运行
名为/context
的基本路径用作网关的入口点
一个名为my-resources
的服务在http://localhost:8091/my-resources
上运行。当/my-resources
不带参数调用时,它会返回所有资源。当使用参数调用它时,它会返回具有相应RID
(如果有)的资源
网关已配置为将传输到http://localhost:8090/context/my-resources/
的所有路径变量(可能没有)转发到uri http://localhost:8091/my-resources/
。
方法一:使用application.yml
spring:
cloud:
gateway:
routes:
- id: route_id
predicates:
- Path=/context/my-resources/**
filters:
- RewritePath=/context/my-resources/(?<RID>.*), /my-resources/$\RID
uri: http://localhost:8091
方法2:使用类似Java的配置
@Bean
public RouteLocator routes(RouteLocatorBuilder routeBuilder)
return routeBuilder.routes()
.route("route_id",
route -> route
.path("/context/my-resources/**")
.filters(f -> f.rewritePath("/context/my-resources/(?<RID>.*)", "/my-resources/$RID"))
.uri("http://localhost:8091")
)
.build();
【讨论】:
【参考方案4】:注意到在使用 rewritePath 时更改 contextPath 的能力似乎被 Spring Boot 2.3.X 中的更改破坏了。并且 RewritePathGatewayFilterFactory.Config 不包含用于在 Hoxton.SR7+ 中传递新 contextPath 的字段。
作为一种解决方法,我创建了一个自定义 RewritePathGatewayFilter 并使用:
ServerHttpRequest request = exchange.getRequest().mutate().contextPath(newContextPath).path(newPath).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());
return chain.filter(exchange.mutate().request(request).build());
【讨论】:
以上是关于Spring Cloud Gateway - 代理/转发 URL 的整个子部分的主要内容,如果未能解决你的问题,请参考以下文章
微服务一文读懂网关概念+Nginx正反向代理+负载均衡+Spring Cloud Gateway(多栗子)