【问题标题】:Spring Cloud Gateway: Does not route request, eventually encounter 413 request entity too largeSpring Cloud Gateway:不路由请求,最终遇到413请求实体太大
【发布时间】:2020-10-06 12:04:45
【问题描述】:

我正在尝试设置一个简单的 Spring Cloud Gateway 示例。

我有 2 个本地运行的 docker 容器,当以下端点被命中时,它们将响应 AAAZZZ

http://localhost:2000/restmessage
http://localhost:2001/restmessage

我正在尝试制作一个简单的网关来路由到这些服务之一。最终会有实际的逻辑来做出这个决定,但现在我只想看到一些工作,并且已经硬编码到第一个实例。

这是我的GlobalFilter

@Component
public class MacFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerWebExchange modifiedExchange = exchange.mutate()
                .request(rq -> rq.uri(
                        UriComponentsBuilder.fromUri(exchange.getRequest().getURI())
                        .host("localhost")
                        .port(2000)
                        .build()
                        .toUri()
                ))
                .build();

//        ServerWebExchangeUtils.setAlreadyRouted(modifiedExchange);


        return chain.filter(modifiedExchange);
    }
}

和属性

spring.cloud.gateway.routes[0].id=routezero
spring.cloud.gateway.routes[0].uri=http://localhost:8081
spring.cloud.gateway.routes[0].predicates[0]=Path=/restmessage

每次我使用 restmessage (http://localhost:8080/restmessage) 访问网关时,都会运行此过滤器。但是如果注释掉的setAlreadyRouted 方法被注释掉了,它会命中数百次。最终 curl 命令失败并返回 413 REQUEST ENTITY TOO LARGE。通过查看 docker 服务的日志,我可以知道它们从未被命中。

$ curl localhost:8080/restmessage -i
HTTP/1.1 413 Request Entity Too Large
content-length: 0

如果我取消注释 setAlreadyRouted 方法,它不再调用数百次,请求立即返回,但响应为空,并且不再调用 docker 容器。

$ curl localhost:8081/restmessage -i
HTTP/1.1 200 OK
content-length: 0

我也尝试过使用 FilterFactoryRouteLocator Bean,但它们都表现出相同的行为。

我一直在搜寻所有文档,但我能找到的所有内容似乎都表明这应该可以工作。谁能帮帮我?

【问题讨论】:

    标签: java spring rest gateway spring-cloud-gateway


    【解决方案1】:

    您要做的是定义后端服务的路由。在您当前的设置中,您正在创建到在端口 8081 上运行的服务的路由,据我在您的描述中看到的,该端口上没有运行任何服务。

    换句话说,如果您有 2 个相同的服务,一个在 localhost:2000 上运行,另一个在 localhost:2001 上运行,您将需要 2 个路由,一个用于一个服务,一个用于另一个。当然,由于服务公开了相同的端点,您将需要一些东西来区分您要路由到哪个服务。例如,这可以通过在您的请求中添加标头来完成。

    示例设置可能是这样的。在您的 application.yaml 中(所以不在您的 application.properties 中,也可以在属性文件中完成,但 yaml 更适合此目的),输入如下内容:

    spring:
      application:
        name: gateway-service
      cloud:
        gateway:
          routes:
            - id: 2000service
              uri: http://localhost:2000
              predicates:
                - Path=/restmessage
                - Header=route, service-one
            - id: 2001service
              uri: https://localhost:2001
              predicates:
                - Path=/restmessage
                - Header=route, service-two
    

    您可以摆脱您的 GlobalFilter 和您定义的属性。现在启动您的应用程序:

    mvn spring-boot:run
    

    然后对您的服务进行 curl(假设您的网关在端口 8080 上运行):

    curl http://localhost:8080/restmessage -H "route: service-one"
    

    您现在应该看到您的请求被路由到您在端口 2000 上运行的服务。

    希望这会有所帮助!

    【讨论】:

    • 感谢您的回复,但不幸的是,我不提前知道我的路线,也无法在配置中填充它们。这个特定的例子很简单,不包括这个细节,但最终我不得不依赖外部服务进行路由。我会根据服务响应构建一个缓存,这样它可以快速运行,但是缓存和路由必须由外部服务决定。所以我真正需要的是一种基于普通旧java中缓存内容动态路由的方法。
    【解决方案2】:

    也许像 eureka 这样的发现中心会解决您的问题。

    • 首先,将docker服务器注册到eureka;
    • 那么,给spring cloud gateway一个eureka配置;
    • 最后,在您的 spring 云网关应用程序类中设置 @EnableDiscoveryClient。

    另外,本期的帖子对您​​有很大帮助:https://github.com/spring-cloud/spring-cloud-gateway/issues/383

    【讨论】:

    • 很遗憾由于环境和要求,无法使用Eureka。
    猜你喜欢
    • 1970-01-01
    • 2014-12-30
    • 2014-12-23
    • 1970-01-01
    • 2012-09-23
    • 2015-10-04
    • 2015-01-25
    • 2014-12-04
    相关资源
    最近更新 更多