Stream / Загрузка файла без сохранения в памяти в Spring Boot - PullRequest
0 голосов
/ 05 февраля 2019

Мое приложение использует Google Cloud Storage для хранения больших файлов и Spring Boot в качестве бэкэнда.

Я только что завершил реализацию контроллера, ответственного за загрузку, следуя тому, что я считал правильным, но поведение я получаюот браузера не то, что я ожидал.

Шаги

Если я попытаюсь загрузить файл, произойдет следующее:

  1. Файл («blob»)чтение из облачного хранилища Google с использованием ReadChannel
  2. Запись канала в ByteArrayOutputStream;
  3. Запись канала с использованием буфера
  4. ByteArrayOutputStream преобразуется в InputStreamResource
  5. Ресурс 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();
            }

    }

1 Ответ

0 голосов
/ 05 февраля 2019

Согласно вашему вопросу, объекты в вашем ведре являются частными, и вы хотите предоставить доступ к ним ограниченной группе людей.Если это так - подписанные URL-адреса - это то, что вам нужно.

Вы можете создать подписанный URL-адрес для определенного объекта в корзине и перенаправить пользователя на сгенерированный URL-адрес, чтобы он сам загрузил файл.

Дополнительная информация: Подписанные URL-адреса GCloud

...