Ответ 1
Возможно, из-за того, что вы указываете больший размер, чем тот, который фактически был отправлен в ответ, а веб-браузер в основном запутался и ждет новых данных? Вы знаете, ZIP сжимает файлы и уменьшает окончательный размер.
Просто не указывайте длину содержимого ответа, если вы не можете эффективно рассчитать его заранее. Контейнер сервлета все равно автоматически отправит его с чанкованным кодированием. Правда, это немного увеличивает издержки и оставляет веб-браузеру неизвестный ход загрузки, но для этого не требуется сначала буферизовать весь ответ в памяти сервера, чтобы вы могли получить правильную конечную длину содержимого ответа.
Если вы действительно хотите рассчитать конечную длину содержимого ответа, вам нужно вместо этого записать все это в ByteArrayOutputStream
а затем получить byte[]
его toByteArray()
. Реальная длина содержимого ответа равна длине byte[]
.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(baos);
// ...
response.setContentLength(baos.size());
response.getOutputStream().write(bytes);
Это только больше памяти, потому что все сначала будет храниться в памяти сервера. Если несколько пользователей делают это одновременно и выходные данные в формате zip относительно велики, то ваш сервер рано или поздно рискует исчерпать память. В качестве другой альтернативы вы можете записать его, используя FileOutputStream
во временный файл, созданный File#createTempFile()
, так что вы можете получить его размер с помощью File#length()
и использовать FileInputStream
для его потоковой передачи непосредственно в OutputStream
ответа обычным способом. Это только медленнее, поскольку вы в основном передаете байты дважды.