Мне было интересно, есть ли способ узнать, закрыл ли клиент соединение StreamingResponseBody
, пока данные все еще записываются в выходной поток. Мой Spring Boot контроллер выглядит так:
@RestController
public class MyController {
@PostMapping(value = "/zip")
public ResponseEntity<StreamingResponseBody> zip(HttpServletResponse response) {
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=download.zip");
StreamingResponseBody responseBody = outputStream -> {
try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {
// loop over files
final ZipEntry zipEntry = new ZipEntry(path);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = bufferedInputStream.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
zipOut.closeEntry();
} catch (IOException e) {
// error handling
}
}
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
}
Приложение берет некоторые файлы и помещает их в ZIP-файл в ответ. При нормальной работе это приложение работает нормально.
Если клиент прерывает загрузку ZIP-файла, приложение продолжает помещать файлы в ZIP-архив, но в конечном итоге происходит сбой с ClientAbortException
(через несколько минут). Вот подробное сообщение об ошибке:
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:351)
at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:776)
at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:681)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:386)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:364)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96)
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:645)
at org.springframework.security.web.util.OnCommittedResponseWrapper$SaveContextServletOutputStream.write(OnCommittedResponseWrapper.java:645)
at java.util.zip.DeflaterOutputStream.deflate(DeflaterOutputStream.java:253)
at java.util.zip.DeflaterOutputStream.write(DeflaterOutputStream.java:211)
at java.util.zip.ZipOutputStream.write(ZipOutputStream.java:331)
Так можно ли было бы остановить обработку, связанную с этим запросом, когда клиент закрывает соединение? В противном случае полезные ресурсы будут потрачены впустую.