// requestは、HttpServletRequest
try {
String requestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
} catch (Exception e) {
// 例外処理
}
または
// requestは、HttpServletRequest
try {
BufferedReader reader = request.getReader();
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
String requestBody = stringBuilder.toString();
} catch (Exception e) {
// 例外処理
}
HttpServletRequest の getReader メソッドを使用する際にループが必要なのは、クライアントから送信されたリクエストボディの内容を全て読み取るためです。以下にその理由を詳しく説明します。
getReader メソッドの動作
getReader メソッドは、リクエストボディを文字単位で読み取るために BufferedReader を返します。BufferedReader は、内部的にバッファリングを行いながら、文字ストリームを効率的に読み取ります。
リクエストボディの読み取り
リクエストボディは任意の長さを持つことができ、単一の呼び出しで全てのデータを読み取ることは保証されていません。従って、以下のようにループを使用してデータを逐次読み取る必要があります。
なぜループが必要か
データの分割読み取り:
ネットワークを介して送信されたデータは、複数のチャンクに分割されて届く可能性があります。単一の readLine 呼び出しでは、リクエストボディ全体を読み取ることはできません。
非同期データ到着:
クライアントから送信されるデータは、サーバーに到着するタイミングが異なるため、非同期に処理する必要があります。BufferedReader の readLine メソッドは、ストリームの終わりに達するまでデータを連続して読み取ります。
ストリームの終端:
BufferedReader はストリームの終わりに達するまでデータを読み続けます。null が返されるまでループを回すことで、全てのデータを確実に取得できます。
まとめ
HttpServletRequest の getReader を使用する際にループが必要なのは、ストリームから送られてくるデータが任意の長さであるため、全てのデータを確実に読み取るためです。BufferedReader を使って、データの終端まで逐次読み取ることで、完全なリクエストボディを取得することができます。
追加情報(2025/4/9)
も大容量リクエストにはNGのコードです
リクエストボディ全体をメモリ上に読み込んで、1つの String に結合してしまう方法です。つまり、
100MBのリクエストが来たら
Javaのヒープに100MB以上(内部文字列のオーバーヘッド含む)が一気に確保される
その結果、複数同時アクセス or GCタイミングによってはOutOfMemoryErrorが発生します。
大容量データ対応のベストプラクティス
✅ ストリーミングで処理する
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
// ここで1行ずつ処理、または一時ファイルに書き出すなど
}
このように、全体を一気に読み込まないようにすることが大切です。
✅ ファイルアップロードなら MultipartFile + ディスク保存
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
File tempFile = File.createTempFile("upload_", ".tmp");
file.transferTo(tempFile);
// 処理後に削除など
return "ok";
}
✅ そもそもAPIで受け取らず、S3や一時ストレージを使う