BufferedReader 不能直接用于读取 HTTP POST Raw Body,因为 Servlet API 输入流仅允许读取一次,且 getParameter()、getInputStream()、getReader() 互斥;若 Content-Type 为表单类型或已调用参数方法,再调用 getReader() 会失败。

在 Web 容器(如 Tomcat、Jetty)中,BufferedReader 不能直接用于读取 HTTP POST 请求的 Raw Body,因为 Servlet API 的 HttpServletRequest 输入流默认只允许读取一次,且一旦调用 getParameter()、getInputStream() 或 getReader() 中的任意一个,其他方法会抛出 IllegalStateException。
为什么直接 new BufferedReader(request.getReader()) 可能失败?
原因有三:
- 如果请求是
application/x-www-form-urlencoded或multipart/form-data类型,容器会自动解析参数,触发内部缓冲,再调用getReader()可能返回空或抛异常; -
getReader()和getInputStream()互斥 —— 二者只能选其一; - 某些容器(如 Tomcat)在调用
getParameter()后会提前消费输入流,导致后续读取为空。
正确读取 Raw Body 的前提条件
必须满足以下三点:
- Content-Type 不是
application/x-www-form-urlencoded或multipart/form-data(否则容器会尝试解析表单,破坏原始流); - 在请求生命周期内,从未调用过
getParameter()、getParameterMap()等参数获取方法; - 使用
request.getReader()或request.getInputStream()之一,且只用一次。
推荐做法:用 BufferedReader 读取纯文本类请求体
适用于 application/json、text/plain、application/xml 等非表单类型:
BufferedReader reader = request.getReader();
StringBuilder body = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
body.append(line);
if (reader.ready()) { // 避免末尾多加换行
body.append("\n");
}
}
String rawBody = body.toString();
注意:readLine() 会自动去掉换行符,如需保留原始换行,请改用 InputStream + InputStreamReader:
InputStream is = request.getInputStream(); InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isr); // 同上逻辑
更健壮的方案:封装成工具方法并处理编码
实际项目中建议统一处理字符编码和流关闭(Servlet 3.1+ 支持 request.getCharacterEncoding()):
- 优先用
request.getCharacterEncoding()获取编码, fallback 到 UTF-8; - 不要手动 close
request.getReader()或getInputStream()—— 容器负责释放; - 若需多次读取(如过滤器中预读 + 后续 Servlet 复用),需借助
HttpServletRequestWrapper缓存 body。
不复杂但容易忽略:只要没碰参数方法、ContentType 合适、只读一次,BufferedReader 就能可靠读取原始请求体。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











