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
相关产品推荐
相关产品推荐

