StreamingResponseBody复用未关闭的OutputStream是否符合预期?请求复用引发异常
Short answer: Absolutely not—this is a bug, not intended behavior. Let's break down what's happening and how to fix it.
Why this is wrong
The StreamingResponseBody (and its associated OutputStream) is built for a single request-response cycle. That OutputStream is tightly bound to the underlying HTTP connection of the specific request you're handling. When you terminate a curl request with ctrl+c, the connection gets abruptly dropped (the "broken pipe" scenario), and the servlet container (like Tomcat or Jetty) immediately cleans up the stream's backing resources. At that point, the stream becomes completely invalid—any later attempt to write to it will throw exceptions like NullPointerException or a broken pipe IOException, exactly what you're encountering.
Why you're seeing reuse
If your system is reusing the same OutputStream instance (same hash code) across different requests, you're almost certainly accidentally caching or sharing the stream (or the StreamingResponseBody itself) in a shared scope—like a static variable, a singleton bean, or a request-scoped bean that's being incorrectly retained. This is a classic mistake that leads to cross-request contamination.
How to fix it
You need to enforce strict per-request isolation for StreamingResponseBody and its stream:
- Never cache the
OutputStream: The stream passed toStreamingResponseBody.writeTo()is only valid for the duration of that method call. Don't store it anywhere outside this method's scope. - Return a fresh
StreamingResponseBodyper request: Every incoming request should get its own instance ofStreamingResponseBody, tailored to that request's specific parameters. - Handle exceptions gracefully: In your
writeToimplementation, catch broken pipe exceptions and log them instead of letting them propagate—this avoids noisy error logs when clients terminate requests early.
Here's a clean example of how this should look:
@GetMapping("/stream") public StreamingResponseBody streamResponse(@RequestParam String param) { // Create a NEW StreamingResponseBody for every request return outputStream -> { try { // Write data specific to this request's parameters byte[] content = String.format("Processing request with param: %s%n", param).getBytes(); outputStream.write(content); outputStream.flush(); } catch (IOException e) { // Handle client-side termination gracefully if (e.getMessage() != null && e.getMessage().contains("Broken pipe")) { log.warn("Client terminated the request early (broken pipe)"); } else { // Rethrow other IO exceptions throw e; } } }; }
Double-check your code for any places where you might be storing the StreamingResponseBody or its OutputStream in a shared variable—that's almost certainly where the issue originates.
内容的提问来源于stack exchange,提问作者aglassman

