Мое приложение использует Google Cloud Storage для хранения больших файлов и Spring Boot в качестве бэкэнда.
Я только что завершил реализацию контроллера, ответственного за загрузку, следуя тому, что я считал правильным, но поведение я получаюот браузера не то, что я ожидал.
Шаги
Если я попытаюсь загрузить файл, произойдет следующее:
- Файл («blob»)чтение из облачного хранилища Google с использованием ReadChannel
- Запись канала в ByteArrayOutputStream;
- Запись канала с использованием буфера
- ByteArrayOutputStream преобразуется в InputStreamResource
- Ресурс inputStream затем передается в ResponseEntity
Неожиданное поведение
Если пользователь переходит к контроллеру загрузки и запрашиваетконкретный файл, файл сначала полностью загружается на сервер, а затем подается клиенту.Между тем, клиент видит, что сервер «не отвечает» (потому что сервер загружает файл), что не очень хорошо.Когда файл будет полностью загружен на сервер, он будет отображаться в «Загружено» очень быстро.
Что я хотел , так это избежать «не отвечающей» части и потокаили файл клиенту, как это обычно происходит при попытке загрузить большой файл, когда вы видите колесо «загрузки» вокруг файла в Chrome.
Любая помощь в понимании того, что не так с приведенным ниже кодомбудет признателен!
Код для контроллера Sring следующий:
@RequestMapping("/**/*")
public ResponseEntity<InputStreamResource> downloadFile(
RedirectAttributes redirectAttributes, HttpServletRequest request, HttpServletResponse response) throws Exception {
String fid = ....
WritableByteChannel channel;
Storage storage = new DownloadAction().getStorage();
BlobId blobId = BlobId.of(BUCKET_ID, blobPath);
Blob blob = storage.get(blobId);
ByteArrayOutputStream writeTo = new ByteArrayOutputStream();
try (ReadChannel reader = blob.reader()) {
channel = Channels.newChannel(writeTo);
ByteBuffer bytes = ByteBuffer.allocate(64 * 1024);
while (reader.read(bytes) > 0) {
System.out.println("here");
bytes.flip();
channel.write(bytes);
bytes.clear();
}
}
channel.close();
writeTo.close();
InputStream tmp = new ByteArrayInputStream(writeTo.toByteArray());
InputStreamResource resource = new InputStreamResource(tmp);
MediaType mediaType = MediaType.parseMediaType(mimeType);
return ResponseEntity.ok()
.contentType(mediaType)
.contentLength(fileSize)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(resource);
} catch (IOException e) {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}