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

Spring Boot如何在单个控制器处理外部API即时响应与回调响应

在同一控制器中获取外部API的即时响应与回调响应的实现方案

核心思路

要在同一个控制器方法中同时拿到外部API的即时响应和后续回调响应,关键是通过请求关联标识将两者绑定,再利用异步等待机制让主请求等待回调结果返回。常用的实现方式是基于内存存储(如ConcurrentHashMap)维护请求的异步任务,配合回调接口完成结果传递。

具体实现方案

1. 定义全局关联存储与工具类

先创建一个用于存储回调任务的全局容器,用来关联请求ID和对应的异步Future:

@Component
public class CallbackTaskHolder {
    // 用ConcurrentHashMap保证线程安全,key为请求关联ID,value为待完成的CompletableFuture
    private final ConcurrentHashMap<String, CompletableFuture<CallbackResponse>> taskMap = new ConcurrentHashMap<>();

    // 注册回调任务
    public void registerTask(String requestId, CompletableFuture<CallbackResponse> future) {
        taskMap.put(requestId, future);
    }

    // 完成回调任务并移除
    public void completeTask(String requestId, CallbackResponse response) {
        CompletableFuture<CallbackResponse> future = taskMap.remove(requestId);
        if (future != null) {
            future.complete(response);
        }
    }

    // 定时清理超时任务(避免内存泄漏)
    @Scheduled(fixedRate = 60000) // 每分钟清理一次已完成/超时的任务
    public void cleanTimeoutTasks() {
        taskMap.entrySet().removeIf(entry -> entry.getValue().isDone() || entry.getValue().isCancelled());
    }
}

2. 修改主控制器方法

在MainController中生成唯一请求ID,调用外部API时将ID传入请求头和Callback参数,然后等待回调任务完成:

@RestController
@RequestMapping("/main")
public class MainController {

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private CallbackTaskHolder taskHolder;

    @PostMapping("/call-api")
    public ResponseEntity<Map<String, Object>> callApi() throws InterruptedException, ExecutionException, TimeoutException {
        // 生成唯一请求关联ID
        String requestId = UUID.randomUUID().toString();

        // 构建外部API请求头,包含Authorization、Content-Type和带requestId的Callback地址
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "your-auth-token");
        headers.set("Callback", "http://mycallback:8080/sendCallback?requestId=" + requestId);

        // 构造请求体
        SamplePlayload requestPayload = createRequestPayload();
        HttpEntity<SamplePlayload> requestEntity = new HttpEntity<>(requestPayload, headers);

        // 调用外部API获取即时响应
        ResponseEntity<String> initialResponseEntity = restTemplate.exchange(
                "http://sample:7070/test",
                HttpMethod.POST,
                requestEntity,
                String.class
        );
        String initialResponse = initialResponseEntity.getBody();

        // 创建异步Future并注册到任务容器
        CompletableFuture<CallbackResponse> callbackFuture = new CompletableFuture<>();
        taskHolder.registerTask(requestId, callbackFuture);

        // 等待回调结果(设置30秒超时,避免无限阻塞)
        CallbackResponse callbackResponse = callbackFuture.get(30, TimeUnit.SECONDS);

        // 封装两个响应返回
        Map<String, Object> result = new HashMap<>();
        result.put("initialResponse", initialResponse);
        result.put("callbackResponse", callbackResponse);

        return ResponseEntity.ok(result);
    }

    private SamplePlayload createRequestPayload() {
        // 构造请求体逻辑
        return new SamplePlayload();
    }
}

3. 修改回调控制器

CallbackController收到回调后,通过requestId找到对应的异步任务并完成:

@RestController
@RequestMapping("/sendCallback")
public class CallbackController {

    @Autowired
    private CallbackTaskHolder taskHolder;

    @PostMapping
    public ResponseEntity<Void> handleCallback(@RequestBody CallbackResponse callbackResponse,
                                               @RequestParam String requestId) {
        // 完成对应的异步任务,传递回调响应
        taskHolder.completeTask(requestId, callbackResponse);
        return ResponseEntity.ok().build();
    }
}

注意事项

  • 超时处理:必须为CompletableFuture.get()设置超时时间,防止请求长期阻塞导致资源耗尽。
  • 内存泄漏:通过定时任务清理已完成或超时的任务,避免ConcurrentHashMap无限膨胀。
  • 线程安全:使用ConcurrentHashMap保证多线程环境下的任务存储安全。
  • 异常处理:需捕获TimeoutException、ExecutionException等异常,避免请求直接报错。

内容的提问来源于stack exchange,提问作者Md. Sakhawath Hossain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:22:45