JAX-RS StreamingOutput 详细讲解
一、StreamingOutput 是什么
StreamingOutput 不是"返回数据对象",而是"你亲手往 HTTP
响应流里写字节"。
它的接口定义:
java
@FunctionalInterface
public interface StreamingOutput {
void write(OutputStream output) throws IOException;
}
核心含义: - JAX-RS 不帮你序列化对象 - 不缓存完整结果 - 直接把 HTTP
Response 的 OutputStream 交给你
二、与普通返回方式的根本区别
普通返回
java
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<User> getUsers() {
return userService.findAll();
}
流程:
- Java 对象
→ MessageBodyWriter
→ JSON
→ 一次性返回
特点: - 数据必须先完整生成 - 占用内存 - 适合小数据
StreamingOutput 返回
java
@GET
@Produces("text/csv")
public StreamingOutput streamCsv() {
return output -> {
output.write("id,name\n".getBytes());
output.write("1,Alice\n".getBytes());
};
}
流程:
- 客户端建立连接
→ 容器打开 OutputStream
→ 调用 write()
→ 边写边发送
特点: - 流式输出 - 几乎不占内存 - 适合大数据、下载
三、为什么说是在"写 HTTP 管道"
OutputStream 就是 TCP 连接上的 HTTP Response Body。
- write():客户端立刻收到
- flush():强制推送缓冲区
- 异常:连接直接中断
你已经进入网络 IO 层。
四、典型使用场景
1. 大数据 CSV 导出
java
@GET
@Produces("text/csv")
public StreamingOutput export() {
return out -> {
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(out, StandardCharsets.UTF_8)
);
writer.write("id,name\n");
for (User u : userService.streamAll()) {
writer.write(u.getId() + "," + u.getName() + "\n");
writer.flush();
}
};
}
2. 长任务实时输出
java
@GET
@Produces(MediaType.TEXT_PLAIN)
public StreamingOutput task() {
return out -> {
for (int i = 1; i <= 5; i++) {
out.write(("step " + i + "\n").getBytes());
out.flush();
Thread.sleep(1000);
}
};
}
五、Response + StreamingOutput(推荐)
java
@GET
public Response download() {
StreamingOutput stream = out -> {
out.write("hello".getBytes());
};
return Response.ok(stream)
.header("Content-Disposition", "attachment; filename=test.txt")
.build();
}
六、常见致命坑
1. 没有返回值概念
java
return out -> {
out.write(data);
};
2. 不要关闭 OutputStream
java
out.close(); // ❌
3. write 后抛异常会导致下载损坏
4. 不会自动 JSON 序列化
java
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(out, obj);
七、什么时候必须用 StreamingOutput
| 场景 | 是否使用 |
|---|---|
| 小 JSON | ❌ |
| 大文件下载 | ✅ |
| 实时输出 | ✅ |
| 普通 REST 查询 | ❌ |
八、核心总结
StreamingOutput = 你控制 HTTP 响应流本身
不是返回数据,而是写网络字节。