カテゴリ: Spring 更新日: 2025/10/18

Spring Bootの大容量レスポンス配信!初心者でもわかるストリーミングとファイル出力の実装方法

Spring Bootの大容量レスポンス配信:ストリーミング/ファイル出力のコツ
Spring Bootの大容量レスポンス配信:ストリーミング/ファイル出力のコツ

先生と生徒の会話形式で理解しよう

生徒

「大きなファイルをSpring Bootでダウンロードさせたいんですけど、メモリが心配です…」

先生

「それはよくある悩みですね。Spring Bootではストリーミングでレスポンスを返すことで、メモリ消費を抑えながら大容量ファイルを送信できますよ。」

生徒

「普通にResponseEntityで返すだけじゃだめなんですか?」

先生

「用途によりますが、大容量のファイルを一気にメモリに載せるのは危険です。ストリームを使えば、効率よく安全に送信できます。詳しく説明しますね!」

1. Spring Bootで大容量レスポンスを扱うときの注意点

1. Spring Bootで大容量レスポンスを扱うときの注意点
1. Spring Bootで大容量レスポンスを扱うときの注意点

Spring Bootでは、通常のResponseEntity@ResponseBodyを使ってレスポンスを返すことができますが、対象が数百MBや数GBに及ぶような大容量ファイルの場合、すべてをメモリに読み込むのは非常に危険です。

そのようなケースでは、ストリーミングによって逐次的にデータを返す方法が効果的です。ストリーミングは、サーバーのメモリ使用量を最小限に抑えつつ、クライアントへリアルタイムにデータを送信できます。

2. Spring Bootでファイルをストリーミングする実装方法

2. Spring Bootでファイルをストリーミングする実装方法
2. Spring Bootでファイルをストリーミングする実装方法

以下のように、OutputStreamを使用して、ファイルを少しずつクライアントに送り出す形で処理を実装できます。これは大容量ファイルでも安定してダウンロードさせる方法です。


@GetMapping("/download")
public void downloadLargeFile(HttpServletResponse response) throws IOException {
    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition", "attachment; filename=large-file.zip");

    try (InputStream inputStream = new FileInputStream("/path/to/large-file.zip");
         OutputStream out = response.getOutputStream()) {

        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }
        out.flush();
    }
}

この実装ではInputStreamを使ってファイルを読み込み、バッファ単位で書き出すことで、大容量でも安定したレスポンスを実現できます。

3. ファイルの種類に応じたContent-Typeの設定

3. ファイルの種類に応じたContent-Typeの設定
3. ファイルの種類に応じたContent-Typeの設定

ファイルの種類によってContent-Typeを適切に設定することで、ブラウザでの動作や表示形式を制御できます。たとえば、PDFなら「application/pdf」、CSVなら「text/csv」などです。


response.setContentType("application/pdf"); // PDFファイルの例

適切なContent-Typeを設定することで、ユーザーにとってより自然なファイルの受け取りが可能になります。

4. SpringのStreamingResponseBodyを使ったストリーミング配信

4. Springの<code>StreamingResponseBody</code>を使ったストリーミング配信
4. SpringのStreamingResponseBodyを使ったストリーミング配信

StreamingResponseBodyを使えば、Spring Bootが用意する仕組みで簡単にストリーミング配信を実装できます。


@GetMapping("/stream")
public ResponseEntity<StreamingResponseBody> streamLargeFile() {
    File file = new File("/path/to/large-file.mp4");

    StreamingResponseBody stream = outputStream -> {
        try (InputStream inputStream = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }
    };

    return ResponseEntity.ok()
        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=large-file.mp4")
        .contentType(MediaType.APPLICATION_OCTET_STREAM)
        .body(stream);
}

StreamingResponseBodyは非同期処理にも対応しており、バックグラウンドでの大容量配信にも適しています。

5. ストリーミングを使うときの注意点と制限

5. ストリーミングを使うときの注意点と制限
5. ストリーミングを使うときの注意点と制限

ストリーミング配信は非常に便利ですが、以下の点に注意が必要です。

  • クライアントが途中で接続を切った場合、例外が発生する可能性があります
  • トランザクション管理と併用する場合、早めにコミットする設計が必要
  • 圧縮処理などを挟む場合は、バッファのサイズや処理速度に注意

6. ファイル出力時のセキュリティ対策とベストプラクティス

6. ファイル出力時のセキュリティ対策とベストプラクティス
6. ファイル出力時のセキュリティ対策とベストプラクティス

ユーザーが任意のファイルパスを指定できるようなAPI設計は危険です。パス・トラバーサル攻撃を防ぐために、ファイルパスは固定または検証されたものに限定すべきです。

また、以下のようなチェックを実装すると安全性が高まります。

  • 存在しないファイルのリクエストには404で返す
  • 拡張子を限定し、不正なファイル出力を避ける
  • ファイル名に../が含まれていないかチェック

7. ファイルダウンロードのログや監査も忘れずに

7. ファイルダウンロードのログや監査も忘れずに
7. ファイルダウンロードのログや監査も忘れずに

大容量ファイルを扱うAPIでは、セキュリティや監査対応のために、誰がいつ何をダウンロードしたかのログを残すことが重要です。

特に企業システムでは、情報漏洩や不正アクセスのリスク管理のため、アクセスログの出力やユーザー認証・認可とセットでダウンロード処理を設計することが推奨されます。

8. Spring Boot + セキュリティで認証付きダウンロードにするには?

8. Spring Boot + セキュリティで認証付きダウンロードにするには?
8. Spring Boot + セキュリティで認証付きダウンロードにするには?

@PreAuthorizeSecurityContextHolderを用いることで、認証されたユーザーのみがファイルを取得できるように制御することが可能です。


@PreAuthorize("hasRole('USER')")
@GetMapping("/secure-download")
public void secureDownload(HttpServletResponse response) {
    // ストリーミング処理
}

これにより、不正アクセスを防ぎ、ファイルごとのアクセス制限を実現できます。

カテゴリの一覧へ
新着記事
Javaのラムダ式で戻り値とvoidの使い方を解説!returnの書き方も完全理解
Javaのメソッド参照とコンストラクタ参照の使い方を完全ガイド!初心者向けに::とClass::newを解説
Javaのラムダ式の書き方を徹底解説!アロー演算子->の基本と使い方
Thymeleafのth:eachの使い方!ループ回数やindexなどの繰り返し処理を学ぼう
人気記事
No.1
Java&Spring記事人気No1
Spring BootとJavaの互換性一覧!3.5/3.4/3.3はJava 21・17に対応してる?
No.2
Java&Spring記事人気No2
Spring Boot JPA入門:エンティティ/リポジトリの基本と作り方
No.3
Java&Spring記事人気No3
Javaの@Validアノテーションを徹底解説!初心者でもわかる入力値検証の基本
No.4
Java&Spring記事人気No4
Springの@Repositoryアノテーションの使い方を徹底解説!初心者でもわかるSpringフレームワークのデータアクセス