Spring:ResponseBodyEmitter.CompleteWithError()和全局异常处理程序

时间:2018-02-09 13:44:27

标签: java spring spring-mvc spring-boot

我在Spring中有异步控制器方法,它使用ResponseBodyEmitter异步下载文件。

    public ResponseEntity<ResponseBodyEmitter> download() {
     ResponseBodyEmitter emitter = new ResponseBodyEmitter();
     taskExecutor.execute(() -> {
      try {
       emitter.send(contentProducer.produce())
       emitter.complete()
      } catch(ContentProducerException e) {
       emitter.completeWithError(e)
      }
     }
     return new ResponseEntity<>(emitter, headers, HttpStatus.OK);
    }

我有一个全局异常处理程序,它处理ContentProducerException并以内部服务器错误响应。

    @ExceptionHandler(value = ContentProducerException.class)
    public final ResponseEntity<Object> handleException(final ContentProducerException e, final WebRequest request) {
    return new ResponseEntity<>("error", headers, httpStatus.INTERNAL_SERVER_ERROR);
    }

但是,当contentProducer抛出ContentProducerException并且正在调用completeWithError()时,会发生以下情况:

  • 全局处理程序handleException()被调用无效
  • 响应为200,浏览器下载空文件

请帮助我了解正在发生的事情以及如何在这种情况下正确返回500(而不是200和无效的文件下载)。

1 个答案:

答案 0 :(得分:0)

taskExecutor.execute在另一个线程中设置为异步。您的方法调度任务然后返回200.它不会等待在返回之前执行任务。从春季文档

  

<强>执行

void execute(java.lang.Runnable task)

Execute the given task.

The call might return immediately if the implementation uses an asynchronous execution strategy, or might block in the case of synchronous execution.

Specified by:
    execute in interface java.util.concurrent.Executor
Parameters:
    task - the Runnable to execute (never null)
Throws:
    TaskRejectedException - if the given task was not accepted

您应该可以修改代码,使其等待:

public ResponseEntity<ResponseBodyEmitter> download() throws Exception {
     ResponseBodyEmitter emitter = new ResponseBodyEmitter();
     Future<Void> task = taskExecutor.submit(() -> {
      try {
       emitter.send(contentProducer.produce())
       emitter.complete()
      } catch(ContentProducerException e) {
       emitter.completeWithError(e)
      }
     }
     task.get();
     return new ResponseEntity<>(emitter, headers, HttpStatus.OK);
    }

get()等待任务完成后再继续,这就是你想要的。