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

Quarkus/Vert.x:如何同时获取解析后的请求负载与原始请求输入流?

同时获取解析后的请求实体与原始请求体的解决方案

针对你遇到的单元测试正常但集成测试中流已关闭无法重置的问题,这里提供两种可行的非响应式解决方案:


方案一:通过请求过滤器提前缓存原始请求体

在请求到达端点前,用过滤器读取并缓存原始请求体,同时将流替换为可重复读取的字节流,避免框架解析实体后流被关闭或无法重置的问题。

实现缓存过滤器

import jakarta.ws.rs.container.ContainerRequestContext
import jakarta.ws.rs.container.ContainerRequestFilter
import jakarta.ws.rs.ext.Provider
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets

@Provider
class RawRequestCachingFilter : ContainerRequestFilter {
    override fun filter(requestContext: ContainerRequestContext) {
        // 读取原始请求体字节
        val rawBodyBytes = requestContext.entityStream.readAllBytes()
        // 转换为字符串缓存
        val rawPayload = String(rawBodyBytes, StandardCharsets.UTF_8)
        
        // 将流替换为可重复读取的ByteArrayInputStream,供框架后续解析实体使用
        requestContext.entityStream = ByteArrayInputStream(rawBodyBytes)
        
        // 将原始请求体存入请求属性,方便端点获取
        requestContext.properties["RAW_REQUEST_PAYLOAD"] = rawPayload
    }
}

修改端点获取缓存内容

@POST
@Path("/path")
@Consumes(APPLICATION_JSON)
fun endpoint(
    body: MyEntity,
    @Context context: ContainerRequestContext,
): RestResponse<String> {
    // 从请求属性中取出预缓存的原始请求体
    val fullPayload = context.properties["RAW_REQUEST_PAYLOAD"] as String
    // 后续业务逻辑...
    return RestResponse.ok(fullPayload)
}

优势:无需修改端点的核心逻辑,过滤器自动完成流的缓存与重置,适配单元测试和集成测试场景,对业务代码侵入性低。


方案二:手动读取原始流并解析实体

直接让端点接收原始输入流,手动完成实体解析,同时保留原始请求体内容,完全控制流的读取过程。

修改端点实现

import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.ws.rs.Consumes
import jakarta.ws.rs.POST
import jakarta.ws.rs.Path
import jakarta.ws.rs.core.MediaType
import jakarta.ws.rs.core.RestResponse
import java.io.InputStream
import java.nio.charset.StandardCharsets

@POST
@Path("/path")
@Consumes(MediaType.APPLICATION_JSON)
fun endpoint(
    rawInputStream: InputStream,
    objectMapper: ObjectMapper, // 注入Jackson的ObjectMapper
): RestResponse<String> {
    // 读取原始请求体字节并转换为字符串
    val rawBodyBytes = rawInputStream.readAllBytes()
    val fullPayload = String(rawBodyBytes, StandardCharsets.UTF_8)
    
    // 手动将原始字节解析为目标实体类
    val body = objectMapper.readValue(rawBodyBytes, MyEntity::class.java)
    
    // 后续业务逻辑...
    return RestResponse.ok(fullPayload)
}

优势:完全绕过框架的自动解析逻辑,避免流被框架关闭或消费的问题,适合需要精细控制请求体处理的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 05:53:13