如何解决Spring Cloud Gateway拦截所有传入和传出的请求
它将是一个后端应用程序,它公开一些REST终结点并可以调用其他后端。 该应用程序在一台主机上运行。我想在同一主机上运行其他应用程序-Sidecar。这应该: 1)Sidecar应该接收后端应用程序的所有传出流量,以添加其他身份验证标头。 2)Sidecar应该会收到所有传入流量,并检查auth标头,然后转发到Backend应用。
Sidecar应该是spring-boot应用程序。我将选择-Spring云网关。
解决1)我将通过代理调用所有后端应用程序请求-代理是Sidecar cloud GW 解决2)我将只公开接收所有传入流量并转发到后端应用的Sidecar端点/ **
当后端应用程序启动传出请求并将Sidecar用作代理时,下一个代码有效
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
@RequestMapping("/**")
public Mono<ResponseEntity<byte[]>> proxy(ProxyExchange<byte[]> proxy,ServerHttpRequest serverHttpRequest) throws Exception {
return proxy.uri(serverHttpRequest.getURI().toString()).forward();
}
}
同时,以上代码将拦截所有外部传入请求,并将其再次发送到Sidecar,从而导致无限循环。
有人建议写Sidecar(Spring云网关),一方面将它用作传出请求的代理,另一方面将所有传入请求转发到后端应用程序
谢谢
解决方法
我已经使用Spring Cloud构建微服务架构;通过spring boot构建的大多数微服务都在eureka中注册。但是有些遗留服务无法轻松迁移到Spring Boot。因此,我们决定使用Sidecar来支持旧版服务;
使用Spring Cloud Gateway作为Sidecar
Spring Cloud提供了 spring cloud辅助工具,但它是使用zuul
构建的。我已将zuul
替换为spring cloud gateway
。
spring cloud sidecar
将在eureka中注册旧服务元信息,而不是在sidecar本身中注册。因此,对旧版服务的请求将不会被sidecar
过滤,因此我们无法管理来自微服务的请求。我修改了spring cloud sidecar
以解决此问题,sidecar
应用程序元信息将在eureka中注册。因此,其他eureka客户端将从eureka服务器而不是旧版服务中找到sidecar application
。
转发进出请求
如何确定来自旧服务或微服务的请求来自何处?请求中有一个来自其他微服务的 自定义标头 ,该标头在旧请求中将不存在。因此,我们使用标头来确定请求是传入还是传出。
我定义了一个SidecarHeaderRoutePredicateFactory
,它扩展了AbstractRoutePredicateFactory
,以构建一个gateway predicate
,它将检查请求头。
如果请求包含 自定义标头 ,这意味着该请求来自其他微服务而不是旧服务,则该请求将转发到旧服务;
否则,请求来自旧服务,将不执行任何操作。 Spring cloud gateway
将通过eureka发现客户端将请求转发到微服务。
来自旧服务的任何请求都具有不同的url模型;网址模板为
http://{sidecarhost:sidecarport}/{invoke-service-name}/api/xxx
。 Spring云网关将通过请求前缀invoke-service-name
确定应将请求转发到何处。
public class SidecarHeaderRoutePredicateFactory
extends AbstractRoutePredicateFactory<SidecarHeaderRoutePredicateFactory.Config> {
public SidecarHeaderRoutePredicateFactory() {
super(SidecarHeaderRoutePredicateFactory.Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config c) {
return exchange -> {
final String value = exchange.getRequest().getHeaders().getFirst(c.header);
return StringUtils.equals(value,c.value);
};
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Config {
private String header;
private String value;
}
}
@Bean
public RouteLocator sidecarRouteLocator(final RouteLocatorBuilder builder) {
final String uri = "http://xxx";
final SidecarHeaderRoutePredicateFactory.Config config =
new SidecarHeaderRoutePredicateFactory.Config(
sidecarProperties.getHeaderName(),sidecarProperties.getHeaderValue());
return builder.routes()
.route(
p -> p.asyncPredicate(
// SidecarHeaderRoutePredicateFactory
sidecarHeaderRoutePredicateFactory()
.applyAsync(config)
).uri(uri)
).build();
}
将自定义标头注入请求
使用GlobalFilter
,我们可以拦截网关中的所有请求,我在此处将自定义标头注入请求中。
public class HeaderInjectGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain) {
ServerWebExchange serverWebExchange = exchange;
if (the request is from legacy service) {
final ServerHttpRequest request = exchange.getRequest();
final ServerHttpRequest newRequest = request.mutate()
.header("headerA","valueA")
.build();
serverWebExchange = exchange.mutate().request(newRequest).build();
}
return chain.filter(serverWebExchange);
}
}
如何在请求中检查auth标头
使用WebFilter
,我们可以检查标题是否在请求中。
public class AuthWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange,WebFilterChain chain) {
final ServerHttpRequest request = exchange.getRequest();
final String value = request.getHeaders().getFirst("auth-header-name");
if (value is exist || auth header is illegal) {
throw new RuntimeException("error");
}
return chain.filter(exchange);
}
}
摘要
我已经用尤里卡和Spring Cloud Gateway构建了Sidecar。这就是我制造小车的过程。我没有尝试过在场景中没有尤里卡的情况下建造边车,但也许定义自定义网关转发规则会起作用。
我希望这会对您有所帮助。谢谢。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。