Spring MVC + StreamingResponseBody - 异常导致 HTTP OK



我在春季MVC控制器中遇到了一个关于StreamingReponseBody的奇怪问题。简单的控制器代码:

@RestController
public class ServerController {
@GetMapping("test")
StreamingResponseBody test(HttpServletResponse response) {
response.setContentType("text/csv");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="test.csv"");

return outputStream -> {
for (int i = 0; i < 5000; i++) {
outputStream.write("Hello".getBytes());
outputStream.write("n".getBytes());
}
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (true) {
throw new RuntimeException("wrong");
}
for (int i = 0; i < 5000; i++) {
outputStream.write("Hello2".getBytes());
outputStream.write("n".getBytes());
}
};
}
}

加上一个控制器建议:

@ControllerAdvice
public class CustomControllerAdvice {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleInternalServerError(Exception exception) {
System.out.println("Unexpected error " + exception);
return new ResponseEntity<>(exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}

}

当我删除抛出子句时,它就像一个魅力。当我在浏览器中输入 URL */test 时,我可以看到我可以下载文件测试.csv。它被正确流式传输了一段时间,我得到了一个 200 HTTP 代码,我可以查看该文件。

但是,抛出异常会导致代码执行一些奇怪的操作。我没有收到 500 HTTP 代码,而是 200 HTTP 代码。在流的末尾,我得到一个"错误"的文本(异常文本o_O(...这是怎么回事?为什么我没有得到 500 HTTP 代码。端点发送的数据不是完整的,但它说尽管有异常,但它没关系。还是我应该使用其他一些流媒体机制,因为这种机制有问题?

感谢您的任何帮助!

纠正我的理解。您开始使用流发送数据,因此您(我猜(不能在某个时刻说"等等,删除我已经发送的数据并更改 http 状态 [可能在开始发送一些数据之前设置为 200]"。因此,当发生异常时,Spring 会重用 OutputStream 并将数据来自:

return new ResponseEntity<>(exception.getMessage()

到同一个输出流中。

一个建议可能是包装代码,这可能会在 try-catch 中使用IOUtils.closeQuietly中引发异常,但效果是您将获得 5000 倍的 Hello 和流结束(所以仍然是 200 http 状态,您正确发送的数据在客户端,但最后没有wrong(

例:

if (true) {
try {
throw new RuntimeException("wrong");
} catch (RuntimeException e) {
IOUtils.closeQuietly(outputStream); #apache
throw e;
}
}

最新更新