Quarkus中如何通过ContainerRequestContext获取请求体
Quarkus LoggingFilter获取请求体实现方案
可以从ContainerRequestContext中获取请求体内容,但要注意Servlet规范中请求体对应的输入流仅支持读取一次,如果直接在过滤器中读取后不做回写,后续业务接口将无法正常获取请求参数,具体实现方式如下:
- 提前过滤不需要读取请求体的场景:GET/DELETE等无请求体的方法、multipart/form-data类型的文件上传请求直接跳过,避免不必要的性能损耗和内存溢出风险。
- 从上下文获取原始输入流,读取指定长度的字节内容转换为字符串格式的请求体。
- 将读取到的字节内容重新封装为字节输入流,调用
setEntityStream()方法回写到请求上下文中,保证后续业务流程可以正常读取请求参数。
改造后的过滤器代码示例
@Provider public class LoggingFilter implements ContainerRequestFilter { private static final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class); // 限制最大读取的请求体长度为1M,避免大请求撑爆内存 private static final int MAX_BODY_CACHE_LENGTH = 1024 * 1024; @Inject JsonWebToken jwt; @Context UriInfo uriInfo; @Context HttpServerRequest request; @Override public void filter(ContainerRequestContext requestContext) throws IOException { String method = requestContext.getMethod(); String path = uriInfo.getPath(); String address = request.remoteAddress().toString(); String operator = jwt.getName(); String requestBody = ""; // 跳过无请求体方法、文件上传类请求 MediaType requestType = requestContext.getMediaType(); if (!("GET".equalsIgnoreCase(method) || "DELETE".equalsIgnoreCase(method)) && requestType != null && !requestType.isCompatible(MediaType.MULTIPART_FORM_DATA_TYPE)) { InputStream originStream = requestContext.getEntityStream(); byte[] bodyBytes = originStream.readNBytes(MAX_BODY_CACHE_LENGTH); requestBody = new String(bodyBytes, StandardCharsets.UTF_8); // 回写输入流,不影响后续接口参数解析 requestContext.setEntityStream(new ByteArrayInputStream(bodyBytes)); } LOGGER.info("{}:{}, From {}, By {}, RequestBody: {}", method, path, address, operator, requestBody); } }
额外提示:如果不需要高度自定义日志格式,Quarkus REST/RESTEasy Reactive已经内置了请求响应日志能力,只需要在配置文件中添加
quarkus.rest.logging.enabled=true即可自动开启,内置实现已经处理了流复用、大请求截断等问题,性能比手写过滤器更优。
内容的提问来源于stack exchange,提问作者Hydra
相关产品推荐
相关产品推荐

