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

如何配置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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 16:01:35