在我的spring 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时,我可以看到我可以下载文件test.csv。它被正确地流式传输了一段时间,我得到了一个200 HTTP代码,我可以查看该文件。
然而,抛出异常会导致代码做一些奇怪的事情。我收到的不是500HTTP代码,而是200HTTP代码。在流的末尾,我得到了一个“错误的”文本(异常文本o_O)...这是怎么回事?为什么我得不到500 HTTP代码。端点发送的不是完整的数据,但它说,尽管有例外,但它是可以的。或者我应该使用其他的流机制,因为这个机制有问题?
谢谢你的帮助!
发布于 2018-10-05 22:55:33
纠正我的理解。你开始使用stream发送数据,所以你(我猜)不能在某个时刻说“等待,删除我已经发送的数据,并在开始发送一些数据之前将http状态设置为200”。因此,当异常发生时,Spring重用OutputStream并将数据放入:
return new ResponseEntity<>(exception.getMessage()
放入相同的OutputStream中。
一种建议是包装可能在try-catch中抛出异常的代码,并使用IOUtils.closeQuietly,但结果是您将获得5000x的Hello和流结束(因此仍然是200Http状态,您正确发送的数据在客户端,但在末尾没有wrong )
示例:
if (true) {
try {
throw new RuntimeException("wrong");
} catch (RuntimeException e) {
IOUtils.closeQuietly(outputStream); #apache
throw e;
}
}发布于 2020-07-31 10:19:01
设置一个HTTP尾部来告诉客户端一切正常!或者在可以的情况下切换到gRPC -在流上处理gRPC错误感觉更自然,客户端连接并为onError、onNext和onComplete事件提供回调。
https://stackoverflow.com/questions/52667734
复制相似问题