Скачать большие файлы через S3 Java Java SDK 2 без записи на сервер - PullRequest
1 голос
/ 26 сентября 2019

Я пытаюсь загрузить большие файлы через AWS, не сохраняя их на сервере, и пока ничего из того, что я пробовал, не сработало.

Вот код, который нужно получить из AWS.

public ResponseInputStream<GetObjectResponse> downloadFile(String key){


     return s3client.getObject(GetObjectRequest.builder().bucket(bucketName).key(key).build(),ResponseTransformer.toInputStream());

}

А вот и контроллер начальной загрузки, который пытается отправить этот поток ответов обратно.

   @RequestMapping(path = "/download", method = GET)
    public ResponseEntity<Resource> downloadOld(@RequestParam String key, Authentication authentication) throws IOException {
        ResponseInputStream<GetObjectResponse> responseStream = this.amazonClient.downloadFile(key);
        InputStreamResource resource = new InputStreamResource(responseStream);
        HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(responseStream.response().contentLength())
                .contentType(MediaType.parseMediaType(responseStream.response().contentType()))
                .body(resource);
    }

У меня частичный успех этого контроллера, у axios response.data действительно есть ответ.И текстовые файлы загружаются правильно. Однако, когда тип содержимого отличается от простого текста (например, application / pdf и т. Д.), Размер загружаемого файла в 1,5 раза превышает исходный размер файла.И само собой разумеется, что он поврежден.(pdf / zip / png) в моем приложении (приложении cordova) ничего не открывается.

Затем я попытался отправить StreamingResponseBody.Вот два примера кода, которые я пробовал. На этот раз оба ответа axios пусты.

@Async
    @RequestMapping(path = "/download", method = GET)
    public ResponseEntity<StreamingResponseBody> download(@RequestParam String key, Authentication authentication) throws IOException {
        ResponseInputStream<GetObjectResponse> responseStream = this.amazonClient.downloadFile(key);
        final StreamingResponseBody out = (os) -> {
            readAndWrite(responseStream, os);
        };
        HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + key.substring(key.lastIndexOf('/') + 1) + "\"");
        headers.add("Content-Type", "application/pdf");
        headers.add("Pragma", "no-cache");
        headers.add("Cache-Control", "no-cache");
        return (new ResponseEntity<>(out, headers, HttpStatus.OK));
    }

Далее попытался отправить ответ без заголовка.

@Async
    @RequestMapping(path = "/download", method = GET)
    public StreamingResponseBody download(@RequestParam String key, Authentication authentication) throws IOException {
        ResponseInputStream<GetObjectResponse> responseStream = this.amazonClient.downloadFile(key);
        return (os) -> {
            readAndWrite(responseStream, os);
        };

    }

Прямая реализация обратного вызова readAndWrite.

private void readAndWrite(final InputStream is, OutputStream os)
            throws IOException {
        byte[] data = new byte[2048];
        int read = 0;
        while ((read = is.read(data)) > 0) {
            os.write(data, 0, read);
        }
        os.flush();
    }

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

Я также попробовал более новый асинхронный подход SDK в сборке, который снова не сработал.Вот клиентский вызов.

@Async
public CompletableFuture<ResponseBytes<GetObjectResponse>> downloadAsync(String key){


    return s3AsyncClient.getObject(GetObjectRequest.builder().bucket(bucketName).key(key).build(), AsyncResponseTransformer.toBytes());

}

(Не удалось найти пример на сайте Amazon AWS о том, как вернуть поток. У них есть один пример, где они использовали ResponseTransformer для сохранения в локальный файл, который нене помогите мне).

Соответствующий контроллер для вышеуказанного AsyncResponse.

 @Async
    @RequestMapping(path = "/downloadAync", method = GET)
    public CompletableFuture<ResponseBytes<GetObjectResponse>> downloadAsync(@RequestParam String key, Authentication authentication) throws IOException {
        return this.amazonClient.downloadAsync(key);

    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...