Скачать файл с AWS lambda

#java #amazon-web-services #file #aws-lambda

Вопрос:

 class DownloadFileHandler RequestHandlerlt;APIGatewayProxyRequestEvent, APIGatewayProxyResponseEventgt; {   @Overrider  public APIGatewayProxyResponseEvent handlerRequest(APIGatewayProxyRequestEvent event, Context context) {  String fileName = event.getQueryStringParameters().get("fileName");  AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);   AmazonS3 s3Client = AmazonS3ClientBuilder.standard()  .withCredentials(new AWSStaticCredentialsProvider(credentials))  .withRegion(Regions.US_EAST_2).build();  GetObjectRequest request = new GetObjectRequest(bucket, fileName);  S3Object objectFile = s3Client.getObject(request);  S3ObjectInputStream objectInputStream = objectFile.getObjectContent();  // latest I was trying this  byte [] fileBytes = new byte[0];   try {  fileBytes = objectInputStream.readAllBytes();  } catch (IOException e) {  e.printStackTrace();  }  }  Maplt;String, Stringgt; headers = new LinkedHashMaplt;gt;();  headers.put("Content-Type", "application/json");  headers.put("Accept", "application/octet-stream");  headers.put("Content-Disposition", String.format(Locale.UK, "attachment; filename=%s", fileName));  headers.put("Content-Length", String.valueOf(fileBytes.length));  // I tried this   JSONObject response = new JSONObject();  response.append("file", objectFile);   APIGatewayProxyResponseEvent responseEvent = new APIGatewayProxyResponseEvent()  .withHeaders(headers)  .withStatusCode(200)  .withIsBase64Encoded(true)  .withBody(Base64.getEncoder().encodeToString(fileBytes));   return responseEvent;  } }  

В приведенном выше коде у меня есть requestHandler файл извлечения из AWS S3, и он должен отправить его в качестве ответа. В приведенном выше коде вы можете видеть, что я пробовал по крайней мере два подхода, не связанных с работой. Я имею в виду, что я могу отправить файл в виде строки, но я не могу загрузить этот файл. То, что я получаю вместо содержимого файла, — это

 DIxMTc1NSAwMDAwMCBuDQowMDAwMjExODg3IDAwMDAwIG4NCjAwMDAyMTE5MTQgMDAwMDAgbg0KMDAwMDIxMjM5MiAwMDAwMCBuDQowMDAwMjE3NDQ3IDAwMDAwIG4NCjAwMDAyMTc1MTcgMDAwMDAgbg0KMDAwMDIxNzc4MiAwMDAwMCBuDQowMDAwMjE3ODYzIDAwMDAwIG4NCjAwMDAyMzExMDAgMDAwMDAgbg0KMDAwMDIzMTEyNyAwMDAwMCBuDQowMDAwMjMxNTA5IDAwMDAwIG4NCjAwMDAyMzY2MDkgMDAwMDAgbg0KMDAwMDIzNjY3OSAwMDAwMCBuDQowMDAwMjM2OTUwIDAwMDAwIG4NCjAwMDAyMzcwMzEgMDAwMDAgbg0KMDAwMDI0NTA4NSAwMDAwMCBuDQp0cmFpbGVyDQo8PC9TaXplIDE2Ny9Sb290IDE4IDAgUi9JbmZvIDE2IDAgUi9JRFs8RTdCRDQzNDY0Mzg0Q0M0OTU1QTVBQTNBRTIzMzQxNUI PDM5RDcyRDQ5OEJGMzFFNDhCMEQ5QjkxODBFOEIzQzVFPl0vUHJldiAyMDI0MzA Pg0Kc3RhcnR4cmVmDQoyNDk0NDgNCiUlRU9GDQo=% [content cut out]  

Поэтому я предполагаю, что это и есть файл. Но по какой-то причине я не могу его загрузить, потому что, когда я сохраняю этот файл, он не может быть открыт, я получаю ошибку типа file damaged etc.

Я был бы признателен за любую помощь в понимании того, почему этот подход не работает? Я не смог найти ни одного примера Java в документации AWS по этому поводу. Большинство из них посвящены Python или JavaScript. И кажется, что я их не понимаю, потому что вижу такой код, как

 response = {  "statusCode" : 200,  "body" : file }  

или что-то подобное. И для меня это означает, что я должен обернуть файл в объект JSON и просто вернуть его из моего метода обработчика. Но это не работает для меня, потому что я получаю то, что вы можете увидеть 2 фрагмента кода выше. Пожалуйста, объясните, что я делаю неправильно и чего я не понимаю?

Комментарии:

1. Типом содержимого в вашем ответе не будет application/json. Это будет что-то вроде изображения/png или приложения/pdf, в зависимости от файла, содержимое которого вы отправляете.

2. Почему в вашем названии говорится, что вы загружаете с AWS Lambda, когда вы загружаете с AWS S3? Навскидку кажется, что данные закодированы в base64.

3. @DavidConrad функция AWS Lambda находится за шлюзом API и перенаправляет загрузку объекта из S3 клиенту API. Таким образом, клиент API загружает из Lambda через шлюз API, а Лямбда загружает из S3, а затем отправляет содержимое файла клиенту. Кроме того, это не идеальное решение (функция Lambda может просто создать предварительно подписанный URL-адрес и 302 перенаправить клиента на него).

4. jarmod ваше предложение звучит разумно, но что в случае, если я хочу отправить различные типы pdf, docx и т. Д.? Я прочитал в документе aws, что вы всегда должны возвращать JSON от обработчиков.

Ответ №1:

Я не уверен, почему этот пост получает минусовые баллы, но неважно. Если бы @jarmod мог понять, что я хочу загрузить с Lambda, и он мог бы указать мне правильное направление создания перенаправленных запросов на файлы, потому что перенос объекта из S3 в Lambda, а затем повторная отправка его по HTTP-неправильный подход, я думаю, что сообщение достаточно ясно.

Вот почему я решил опубликовать свое решение, которое благодаря @jarmod я смог придумать. В этом обработчике я использую S3Presinger , который, на мой взгляд, очень полезен, если кто-то создаст API с шлюзами AWS, которые используют AWS Lambda и хотят загружать файлы, хранящиеся на AWS S3.

 public class DownloadFileHandler implements RequestHandlerlt;APIGatewayProxyRequestEvent, APIGatewayProxyResponseEventgt; {  @Override  public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) {  String bucket = "";   try (InputStream input = new FileInputStream("./config/application.properties")) {  Properties properties = new Properties();  properties.load(input);   bucket = properties.getProperty("bucket");  } catch (IOException e) {  e.printStackTrace();  }   String fileName = event.getQueryStringParameters().get("fileName");   S3Presigner presigner = S3Presigner.builder().build();   GetObjectPresignRequest presignRequest = GetObjectPresignRequest  .builder()  .signatureDuration(Duration.ofMinutes(10))  .getObjectRequest(GetObjectRequest.builder().bucket(bucket).key(fileName).build())  .build();   PresignedGetObjectRequest presignedGetObjectRequest = presigner.presignGetObject(presignRequest);   String presignedURL = presignedGetObjectRequest.url().toString();  Maplt;String, Stringgt; headers = new LinkedHashMaplt;gt;();  headers.put("Content-Type", "application/json");  headers.put("Location", presignedURL);   APIGatewayProxyResponseEvent responseEvent = new APIGatewayProxyResponseEvent()  .withHeaders(headers)  .withStatusCode(302);   return responseEvent;  } }