使用InputStream#read(byte[])读取HttpServletRequest请求体时内容不完整
问题根因
- 核心错误是对
InputStream.read(byte[])方法的行为理解存在偏差:该方法不会保证一次性填满传入的字节数组,仅会返回当前可读取的字节数(至多为数组长度)。当请求体数据较大、TCP传输未完全到达缓冲区时,单次调用read只能拿到部分数据,就会出现截断问题。 HttpServletRequest#getReader()的readLine()方法内部已实现循环读取逻辑,会一直读取到换行符或流结束位置,因此可以正常获取完整请求体。- 现有写法还存在兼容性缺陷:
request.getContentLength()仅在非分块传输(请求头带Content-Length字段)的场景下有有效值,如果GitHub Webhook触发的是chunked分块传输请求,该方法会返回-1,会直接导致数组初始化报错。
修复代码
import java.nio.charset.StandardCharsets; // 完整读取请求体的正确逻辑 InputStream inputStream = request.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int readLen; // 循环读取直到流结束 while ((readLen = inputStream.read(buffer)) != -1) { baos.write(buffer, 0, readLen); } byte[] bodyBytes = baos.toByteArray(); // 写入文件逻辑 try (FileWriter fw = new FileWriter(new File("./payload.txt"))) { for(byte i : bodyBytes) fw.write("0x" + String.format("%02x ", i) + " "); fw.write("\n\n\n"); // 显式指定字符集避免不同环境乱码 fw.write(new String(bodyBytes, StandardCharsets.UTF_8)); }
额外注意事项
- 请求体的输入流是消费型的,读取一次就会失效,不要同时调用
getInputStream()和getReader(),也不要重复读取同一个流。 - 如果使用Spring等框架,可直接借助封装好的工具类读取请求体,避免手动处理流的逻辑漏洞。
内容的提问来源于stack exchange,提问作者Sneakyguy6
相关产品推荐
相关产品推荐

