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

如何在Spring Boot REST服务中为客户端请求分批返回响应?

嘿,这个问题我熟!你现在的代码之所以只能返回第一个任务的结果,是因为HTTP默认是「一次请求对应一次响应」——循环里第一次return就直接结束了整个请求,后面的任务结果根本没机会发出去。要实现「一个请求返回多个响应,每个任务完成就推一个结果」,最适合的技术就是Server-Sent Events(SSE),下面给你详细的实现方案:

解决方案:用SSE实现任务结果逐个推送

Spring Boot 服务端实现

我们可以用Spring提供的SseEmitter来管理长连接,逐个推送任务执行结果。修改你的接口如下:

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

import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
public class ExecutionController {

    @PostMapping("/runExecution")
    public SseEmitter runExecution(@RequestBody List<Object> taskList) { // 替换成你实际的任务列表类型
        // 设置连接超时时间(比如30分钟,避免无意义的长连接占用资源)
        SseEmitter emitter = new SseEmitter(TimeUnit.MINUTES.toMillis(30));

        // 用异步线程处理任务,避免阻塞Spring的请求线程
        new Thread(() -> {
            try {
                for (Object task : taskList) {
                    // 1. 执行你的业务逻辑,替换成实际任务处理代码
                    Object taskResult = executeBusinessTask(task);

                    // 2. 向客户端推送当前任务的结果
                    emitter.send(SseEmitter.event()
                            .name("task-finished") // 自定义事件名称,客户端可按需过滤
                            .data(taskResult)); // 任务结果数据

                    // 模拟任务耗时(实际场景删除此行)
                    Thread.sleep(1500);
                }

                // 所有任务完成后,发送结束信号
                emitter.send(SseEmitter.event()
                        .name("all-done")
                        .data("10个任务全部执行完成!"));
                emitter.complete(); // 主动结束SSE连接
            } catch (Exception e) {
                emitter.completeWithError(e); // 出错时结束连接并返回错误信息
            }
        }).start();

        return emitter;
    }

    // 模拟业务任务执行,替换成你的实际逻辑
    private Object executeBusinessTask(Object task) {
        return String.format("任务[%s]执行成功,结果:处理完成", task.toString());
    }
}

服务端关键细节:

  • SseEmitter是Spring封装的SSE工具,专门用来处理服务器向客户端的流式推送
  • 任务必须放在异步线程里执行,否则会阻塞Spring的请求线程,影响其他接口服务
  • 可以给每个推送事件设置name,客户端能根据事件名称区分「单个任务完成」和「全部任务完成」等不同消息

AngularJS 客户端实现

AngularJS可以通过原生EventSourceAPI接收SSE推送(注意:EventSource默认只支持GET请求,所以推荐分两步处理:先POST提交任务,再GET建立SSE连接)

客户端代码示例

angular.module('taskApp', [])
.controller('TaskCtrl', function($http, $scope) {
    var vm = this;
    vm.taskList = ["任务1", "任务2", ..., "任务10"]; // 你的任务列表
    vm.executionResults = [];

    // 第一步:提交任务列表到服务器
    $http.post('/runExecution/submit', vm.taskList)
        .then(function(res) {
            var taskId = res.data.taskId; // 服务器返回任务唯一标识
            // 第二步:建立SSE连接接收实时结果
            var eventSource = new EventSource(`/runExecution/results/${taskId}`);

            // 监听单个任务完成事件
            eventSource.addEventListener('task-finished', function(event) {
                var result = JSON.parse(event.data);
                vm.executionResults.push(result);
                $scope.$apply(); // 触发Angular视图更新
            });

            // 监听全部任务完成事件
            eventSource.addEventListener('all-done', function(event) {
                vm.executionResults.push(event.data);
                $scope.$apply();
                eventSource.close(); // 任务全部完成后关闭连接
            });

            // 监听连接错误
            eventSource.addEventListener('error', function(event) {
                console.error('SSE连接异常:', event);
                eventSource.close();
            });
        })
        .catch(function(err) {
            console.error('提交任务失败:', err);
        });
});

配套新增Spring Boot GET接口

为了支持上述客户端逻辑,需要新增一个接口用来返回对应任务的SSE流:

@GetMapping("/runExecution/results/{taskId}")
public SseEmitter getTaskResults(@PathVariable String taskId) {
    // 根据taskId关联之前提交的任务,推送实时执行结果
    // 核心逻辑和runExecution方法类似,可结合缓存/消息队列实现任务状态跟踪
    SseEmitter emitter = new SseEmitter(TimeUnit.MINUTES.toMillis(30));
    // 此处省略任务结果推送的具体逻辑,可复用之前的异步任务处理逻辑
    return emitter;
}

客户端关键细节:

  • EventSource是处理SSE的标准API,用法简单且原生支持断连重连
  • 每次获取到新结果后要调用$scope.$apply(),因为Angular无法自动感知非Angular上下文的变量变化
  • 如果必须用POST请求直接建立SSE连接,可以用$http的流式响应处理,但实现复杂度会更高,不推荐

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:20:49