#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; } }