You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus 3.17.6 Rest API大JSON payload报400错误求助

问题排查与解决方案

一、配置排查

当前配置遗漏了Resteasy自身的输入流大小限制,Quarkus的HTTP body限制和Resteasy的输入流限制是独立的,需补充以下配置到application.properties:

# 覆盖Resteasy默认的输入流大小限制,与HTTP body限制保持一致
quarkus.resteasy.max-input-stream-size=4G
# 确保HTTP body限制配置无多余空格(原配置的空格不影响,规范写法如下)
quarkus.http.limits.max-body-size=4G
quarkus.http.limits.max-form-attribute-size=2000M
quarkus.management.limits.max-body-size=2G

额外检查项:

  • 启动Quarkus时查看日志,确认是否输出类似HTTP body size limit is set to 4294967296 bytes的信息,验证配置是否生效
  • 若部署时使用了网关/反向代理(如Nginx),需同步调整代理的请求体大小限制(如Nginx的client_max_body_size)
  • 开启Debug日志排查拒绝原因:
    quarkus.log.level=DEBUG
    quarkus.log.category."io.quarkus.http".level=DEBUG
    

二、大Payload处理代码示例

当请求体超过100MB时,直接绑定到List<EngineFile>会导致Quarkus提前解析请求体触发限制,需改用InputStream或Multi<Buffer>手动解析。

示例1:使用InputStream + Jackson解析

适合一次性加载到内存(确保JVM堆内存足够容纳payload):

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.util.List;

@Path("/refresh")
public class RefreshResource {

    @Inject
    ObjectMapper objectMapper;

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response refresh(InputStream inputStream) throws Exception {
        // 解析InputStream为List<EngineFile>
        List<EngineFile> files = objectMapper.readValue(
            inputStream,
            objectMapper.getTypeFactory().constructCollectionType(List.class, EngineFile.class)
        );

        System.out.println("Received " + files.size() + " files");
        // 执行业务逻辑
        return Response.ok("Refresh Complete").build();
    }
}

示例2:使用Multi流式收集(Mutiny)

适合分块接收请求体,避免一次性占用大量内存:

import io.smallrye.mutiny.Multi;
import io.vertx.mutiny.core.buffer.Buffer;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.util.List;

@Path("/refresh")
public class RefreshResource {

    @Inject
    ObjectMapper objectMapper;

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response refresh(Multi<Buffer> bufferMulti) throws Exception {
        // 收集所有分块Buffer为完整字节数组
        byte[] fullPayload = bufferMulti
            .collect()
            .with(Buffer::buffer)
            .await()
            .indefinitely()
            .getBytes();

        // 解析为List<EngineFile>
        List<EngineFile> files = objectMapper.readValue(
            new ByteArrayInputStream(fullPayload),
            objectMapper.getTypeFactory().constructCollectionType(List.class, EngineFile.class)
        );

        System.out.println("Received " + files.size() + " files");
        // 执行业务逻辑
        return Response.ok("Refresh Complete").build();
    }
}

示例3:Jackson流式解析(避免OOM)

针对超大型payload,逐个解析EngineFile对象,无需一次性加载整个列表到内存:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;

@Path("/refresh")
public class RefreshResource {

    @Inject
    ObjectMapper objectMapper;

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response refresh(InputStream inputStream) throws Exception {
        int processedCount = 0;
        try (JsonParser parser = objectMapper.createParser(inputStream)) {
            // 跳过JSON数组的起始标记
            parser.nextToken();
            // 逐个解析数组中的对象
            while (parser.nextToken() != null) {
                if (parser.getCurrentToken().isStartObject()) {
                    EngineFile file = parser.readValueAs(EngineFile.class);
                    // 对单个file执行业务逻辑(如写入数据库、文件)
                    processedCount++;
                }
            }
        }

        System.out.println("Processed " + processedCount + " files");
        return Response.ok("Refresh Complete").build();
    }
}

内容的提问来源于stack exchange,提问作者Vinod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 02:32:08