如何配置Swagger-UI异步接收并展示Mutiny Multi返回的大量数据?
解决Swagger UI加载Mutiny Multi流式大数据响应卡顿崩溃的问题
问题本质
Swagger UI默认会把完整响应加载到内存后才解析渲染,哪怕后端通过Mutiny Multi实现了分块流式返回(Transfer-Encoding: chunked),它也不会实时处理数据,大数据量下直接撑爆浏览器内存导致无响应或崩溃。而curl这类工具天然支持分块传输,会实时输出数据,所以不受影响。
解决方案
1. 用OpenAPI注解标记流式响应
通过@Extension给API响应添加自定义扩展,明确告诉Swagger UI这是一个流式返回的接口,方便后续自定义逻辑识别:
import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.media.Content; import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; import org.eclipse.microprofile.openapi.annotations.extensions.Extension; import io.smallrye.mutiny.Multi; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @Path("/large-dataset") public class LargeDataResource { @GET @Operation(summary = "获取大数据流式响应") @APIResponses(value = { @APIResponse( responseCode = "200", description = "流式返回的数据项列表", content = @Content( mediaType = "application/json", schema = @Schema(type = "array", implementation = DataItem.class), extensions = @Extension(name = "x-stream", value = "true") ) ) }) public Multi<DataItem> streamLargeData() { // 你的Mutiny Multi数据生成逻辑 return Multi.createFrom().items(DataItem::generateLargeDataset); } public static class DataItem { private String id; private String content; // getter、setter、生成逻辑 public static DataItem generateLargeDataset() { // ... return new DataItem(); } } }
2. 自定义Swagger UI的流式响应处理逻辑
仅靠注解还不够,需要修改Swagger UI的行为,让它实时接收并渲染分块数据:
- 在Quarkus项目的
src/main/resources/META-INF/resources目录下创建stream-handler.js文件,写入自定义拦截逻辑:
// 拦截Swagger UI的响应处理,针对标记了x-stream的接口做流式渲染 window.onload = function() { const originalResponseInterceptor = ui.getResponseInterceptor(); ui.setResponseInterceptor((response, context) => { // 从OpenAPI定义中获取当前接口的x-stream标记 const operation = context.operation; const isStream = operation?.responses?.['200']?.content?.['application/json']?.['x-stream'] === 'true'; if (isStream && response.body) { // 替换默认渲染逻辑,将响应转为可滚动文本避免DOM过载 response.body = `<div style="max-height: 400px; overflow-y: auto; white-space: pre-wrap;">⚠️ 流式响应实时展示:\n${response.body}</div>`; } return originalResponseInterceptor ? originalResponseInterceptor(response, context) : response; }); };
- 在
application.yml中配置Swagger UI加载这个自定义脚本:
quarkus: swagger-ui: custom-javascript: "stream-handler.js" syntax-highlight: false # 保留之前的禁用配置,减少性能消耗
3. 额外优化:改用换行分隔JSON格式
如果接口不需要严格的JSON数组格式,可以将媒体类型改为application/x-ndjson(换行分隔JSON),Swagger UI对这种格式的兼容性更好,也更容易实现流式渲染:
@Content( mediaType = "application/x-ndjson", schema = @Schema(implementation = DataItem.class), extensions = @Extension(name = "x-stream", value = "true") )
同时修改后端返回的Multi,确保每个数据项单独换行:
public Multi<String> streamLargeData() { return Multi.createFrom().items(DataItem::generateLargeDataset) .map(item -> objectMapper.writeValueAsString(item) + "\n"); }
总结
通过OpenAPI注解标记流式特性,再配合Swagger UI的自定义脚本修改渲染逻辑,就能避免大数据量下的浏览器崩溃问题。如果需要更极致的实时渲染体验,改用application/x-ndjson格式会更省心。
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

