You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Spring Rest Controller流式发送文本分片及就绪数据分片?

How to Stream Text Chunks from a Spring REST Controller

Hey there! Let's walk through two practical approaches to send text data in chunks from a Spring REST Controller as soon as each piece is ready—this is perfect for long-running tasks, real-time updates, or avoiding forcing clients to wait for a huge payload to finish processing.

1. Using StreamingResponseBody (Basic Sequential Streaming)

This is Spring's built-in tool for streaming responses directly to the client without buffering the entire payload. It’s ideal when you have a sequence of data chunks to send one after another.

Controller Implementation

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;

@RestController
public class StreamingTextController {

    @GetMapping(value = "/stream-text", produces = MediaType.TEXT_PLAIN_VALUE)
    public StreamingResponseBody streamTextChunks() {
        return outputStream -> {
            // Simulate generating text chunks over time (replace with your actual logic)
            String[] textChunks = {"First chunk ready!\n", "Second chunk coming in...\n", "Third chunk here!\n", "Final chunk delivered!\n"};
            
            for (String chunk : textChunks) {
                // Write the chunk to the output stream
                outputStream.write(chunk.getBytes());
                // Flush immediately to ensure the client gets the chunk right away
                outputStream.flush();
                // Simulate processing delay between chunks (adjust as needed)
                TimeUnit.SECONDS.sleep(1);
            }
        };
    }
}

Key Details:

  • No Buffering: Spring automatically sets Transfer-Encoding: chunked in the response headers, so each chunk is sent as soon as you call flush().
  • Error Handling: Wrap the loop in a try-catch block if you need to handle exceptions mid-stream (e.g., close the stream gracefully if processing fails).
  • Use Case: Great for exporting large files, streaming log data, or any scenario where you need to send a continuous stream of text.

2. Using Server-Sent Events (SSE) with SseEmitter

If you need to send event-driven, real-time updates (like task progress notifications or live status updates), SSE is a better fit. It establishes a persistent connection, letting the server push chunks whenever new data is ready.

Controller Implementation

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@RestController
public class SseStreamingController {

    @GetMapping("/sse-stream-updates")
    public SseEmitter streamSseEvents() {
        // Set a timeout (e.g., 30 minutes) to keep the connection alive
        SseEmitter emitter = new SseEmitter(TimeUnit.MINUTES.toMillis(30));

        // Run chunk generation in a separate thread to avoid blocking the Spring MVC thread pool
        new Thread(() -> {
            try {
                // Send an initial welcome message
                emitter.send("Starting real-time updates...\n");
                
                // Simulate dynamic chunk generation (replace with your actual data source)
                for (int i = 1; i <= 5; i++) {
                    String progressUpdate = String.format("Task progress: %d/5 completed\n", i);
                    // Send the chunk as an SSE event (you can add event IDs/types too)
                    emitter.send(SseEmitter.event().data(progressUpdate));
                    TimeUnit.SECONDS.sleep(1);
                }
                
                // Mark the stream as complete when done
                emitter.complete();
            } catch (IOException | InterruptedException e) {
                // Handle errors (e.g., client disconnected unexpectedly)
                emitter.completeWithError(e);
            }
        }).start();

        return emitter;
    }
}

Client-Side Example (JavaScript)

To receive the SSE stream in a browser:

const eventSource = new EventSource('/sse-stream-updates');

eventSource.onmessage = function(event) {
    console.log('Received update:', event.data);
    // Append to UI, update progress bar, etc.
};

eventSource.onerror = function(error) {
    console.error('Stream error occurred:', error);
    eventSource.close();
};

Key Details:

  • Persistent Connection: SSE keeps the HTTP connection open, so the server can push updates anytime new data is available.
  • Event Metadata: You can add event IDs, custom event types, and retry intervals using SseEmitter.event() (e.g., event().id("update-1").name("progress").data(chunk)).
  • Use Case: Perfect for live notifications, task progress tracking, or any scenario where you need to push updates to the client in real time.

Which Approach Should You Pick?

  • Go with StreamingResponseBody for one-way, sequential streaming of large content (like exporting logs or large text files).
  • Use SSE with SseEmitter for real-time, event-driven updates where the server needs to initiate pushes to the client.

内容的提问来源于stack exchange,提问作者madcolonel10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:29:05