【问题标题】:Can't return large JSON response using Webflux - it fails with both netty and jetty无法使用 Webflux 返回大型 JSON 响应 - netty 和 jetty 均失败
【发布时间】:2020-01-23 22:34:08
【问题描述】:

我想从 webflux 端点返回一个大的(3 到 9 Mb 之间)json 正文。在这一点上,我只是试图将它作为Mono<ResponseEntity<String>> 返回——完全绕过任何序列化/反序列化。但是,在大多数情况下,它只返回实际字符​​串的一部分。 Content-Type 是正确的,但发送的字节不匹配 - 通常相差一个 Mb 或更多,但肯定短了几百 k。

您将在下面看到 Content-Type 正在设置(在较低级别),因此它不会将其发送到分块。既然 chunked 是默认设置,为什么会这样呢?它发生在 netty 或 jetty 上。

当我在发送 ResponseEntity 之前输出标头时,它显示传输编码:分块。然而,响应头(在 curl、chrome、Python 请求库中)都显示 Content-Length 而不是分块。

// IN CONTROLLER
log.info(response.getHeaders());
return Mono.just(new ResponseEntity<>(findByApplicationId(id), HttpStatus.OK));

这将记录以下[transfer-encoding:"chunked"]

// IN TERMINAL WITH CURL
MBP:my-test em$ curl -v localhost:8888/api/thing/0  > /dev/null
* TCP_NODELAY set
* Connected to localhost (::1) port 8888 (#0)
> GET /api/thing/0 HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 5198562
<
{ [16308 bytes data]
100 5076k  100 5076k    0     0  16.0M      0 --:--:-- --:--:-- --:--:-- 16.0M
* Connection #0 to host localhost left intact

为什么要在上面设置 Content-Length - chunked 去哪里了?

报告的 Content-Length 和实际收到的字符串不匹配是很常见的(显然被截短了)

为了完整起见,这是我的 POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>bugfix-group</groupId>
    <artifactId>webflux-jsonb</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>webflux-jsonb</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

【问题讨论】:

  • 你永远不应该在响应头中设置Transfer-Encoding,这是由容器来做的。
  • 请在您的代码中包含a minimal, complete, verifiable example,而不仅仅是maven pom。您的 2 行不足以提供正确的答案。
  • 您好 Joakim,感谢您的回复。我从来没有设置它,但它在发送响应之前已经设置(如预期的那样),但是它被 Content-Length 覆盖在较低级别的地方,我不知道为什么。
  • 不要专注于Content-LengthTransfer-Encoding,一旦你提供了minimal, complete, and verifiable example,那么其他人可以帮助你。
  • 显然在您未提供的代码中做了一些事情。如果您希望我们为您提供帮助,您需要提供完整的图片。

标签: spring-boot spring-webflux embedded-jetty reactor-netty


【解决方案1】:

编辑:我认为这在 Spring 5.1.12.RELEASE 或 5.2.2.BUILD-SNAPSHOT 中已修复。在我的演示应用程序中确认,我现在可以在之前被切断的地方获得大量响应。


根据经验测试,我有理由相信这是 Spring 5.1.6/Spring Boot 2.1.5 及更高版本中的错误。你可以在这里评估我的发现:

(提交给 Spring 的问题) https://github.com/spring-projects/spring-framework/issues/24128

(演示问题的存储库) https://github.com/opentable/webflux-large-response-spring

一些问题:

  • 您使用的是 Jetty 服务器,还是其他服务器(例如 Reactor Netty)?
  • 当您能够重现问题时,您在什么环境中运行应用程序(例如,在 IDE 中本地、在 docker 容器中等?)
  • 数据被截断的响应大小是否一致?

【讨论】:

  • 我很高兴听到可能有修复。这个问题只发生在 Jetty 上。我通过切换到 Netty 解决了这个问题。我认为它总是在 Docker 容器中运行,在 docker-compose 和 Open Shift 中都失败了。至于截止点,它从请求到请求略有变化,但总是会返回至少 75-80% 的有效负载 - 轶事。感谢您的反馈!
猜你喜欢
  • 2019-07-05
  • 1970-01-01
  • 1970-01-01
  • 2015-05-27
  • 2013-11-24
  • 1970-01-01
  • 2016-10-10
  • 2015-12-11
  • 2020-08-24
相关资源
最近更新 更多