Когда вы открываете поток вывода, отправляются заголовки. период.
С этого момента нет возврата. Вы не можете сначала открыть выходной поток, а потом - go: Ой, подождите! Нет! неважно! плохой запрос!
Вот как это работает - вы выбираете сторону и придерживаетесь ее. Вы можете:
- Сделать это самостоятельно; используйте
response
и доступные там методы для настройки ответа; вы можете установить заголовки, код возврата и сообщение, а также получить выходной поток для тела ответа и таким образом отправлять данные. Если вы сделаете это, вы не сможете ТАКЖЕ вернуть ResponseEntity! - Do НЕ даже добавить параметр HttpServletResponse и вместо этого вернуть объект ResponseEntity.
Вы делаете и то, и другое, что запрещено.
Я искренне удивлен; spring немного сломан и должен генерировать исключения здесь, поскольку он не может обслуживать то, что вы просите его здесь.
NB: Обратите внимание, что тип исключения обычно более информативен, чем сообщение (многие исключения даже не имеют сообщение).
Собираем все вместе:
public ResponseEntity<?> downloadDocument(@PathVariable("docId") Long docId) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
docService.downloadDocument(docId, baos);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
.body(baos.toByteArray());
} catch(Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
'toString' по умолчанию печатает собственный тип, если есть не является сообщением, а его собственный тип плюс сообщение, если оно есть, поэтому вы получаете, например:
NullPointerException
или
NullPointerException: parameter foo
, что вы хотите (вместо буквальной пустой строки в первом случае и просто «параметр foo» во втором, что тоже не особо информативно).
сообщения обычно не обязательно имеют смысл без контекста типа исключения.
NB: это кэширует все содержимое загруженного документа в память сервера перед его отправкой. Если документ большой, это плохая идея, но если вы хотите «передать» его, у вас есть довольно серьезная проблема, присущая протоколу HTTP : как только вы начнете отправлять, вы уже отправил «статус ошибки» (т.е. вы уже отправили 200 OK), поэтому, если процесс загрузки документа вызывает исключение на полпути, вы не можете go назад и отправить сообщение об ошибке. Вам нужен какой-то проводной протокол, по которому вы отправляете тело по частям и у вас есть код типа, который вы отправляете, чтобы получатель мог сканировать их и знал, что `` этот тип означает, что идет больше данных '', и `` этот тип означает произошла ошибка, и теперь я могу прочитать описание ошибки ». Все становится довольно сложно. Кешируя это, вы избегаете этого беспорядка. Но если этот документ может быть очень большим, вам придется иметь дело с вышеуказанным, быстрых исправлений нет.