Spring MVC + StreamingResponseBody - исключение вызывает HTTP OK - PullRequest
0 голосов
/ 05 октября 2018

У меня странная проблема с StreamingReponseBody в моем весеннем контроллере MVC.Код простого контроллера:

    @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);
    }

}

Когда я удаляю предложение throw, оно работает как талисман.Когда я ввожу URL * / test в браузер, я вижу, что могу загрузить файл test.csv.Некоторое время он транслируется корректно, и я получаю HTTP-код 200, и я могу просмотреть файл.

Однако, выбрасывая исключение, код делает некоторые странные вещи.Я не получаю код HTTP 500, но код HTTP 200.В конце потока я получаю "неправильный" текст (текст исключения o_O) ... Что здесь происходит?Почему я не получаю 500 HTTP-код.Конечная точка отправляет не полные данные, но говорит, что это нормально, несмотря на исключения.Или я должен использовать какой-то другой механизм потоковой передачи, потому что он неисправен?

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 05 октября 2018

Исправьте мое понимание.Вы начали отправлять данные с использованием потока, поэтому вы (я полагаю) в какой-то момент не можете сказать «подождите, удалите данные, которые я уже отправил, и измените статус http [который установлен на 200, вероятно, непосредственно перед началом отправки некоторых данных]».Поэтому, когда возникает исключение, Spring повторно использует OutputStream и помещает данные из:

return new ResponseEntity<>(exception.getMessage()

в тот же OutputStream.

Одним из предложений может быть перенос кода, который потенциально может вызватьисключение в try-catch и использование IOUtils.closeQuietly, но в результате вы получите 5000x Hello и end of stream (так что все равно 200 http статус, данные, которые вы отправляете правильно, находятся на стороне клиента, но без wrong в конце)

Пример:

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