Как вернуть двоичные данные из лямбда-функции в AWS в Python?
Я не могу заставить Python Lambda возвращать двоичные данные. Шаблон узла для миниатюрных изображений работает нормально, но я не могу заставить работать Python-лямбду. Ниже приведены соответствующие строки из моей лямбды. print("image_data " + image_64_encode)
печатает изображение в кодировке base64 в журналах.
def lambda_handler(event, context):
img_base64 = event.get('base64Image')
if img_base64 is None:
return respond(True, "No base64Image key")
img = base64.decodestring(img_base64)
name = uuid.uuid4()
path = '/tmp/{}.png'.format(name)
print("path " + path)
image_result = open(path, 'wb')
image_result.write(img)
image_result.close()
process_image(path)
image_processed_path = '/tmp/{}-processed.png'.format(name)
print("image_processed_path " + image_processed_path)
image_processed = open(image_processed_path, 'rb')
image_processed_data = image_processed.read()
image_processed.close()
image_64_encode = base64.encodestring(image_processed_data)
print("image_data " + image_64_encode)
return respond(False, image_64_encode)
def respond(err, res):
return {
'statusCode': '400' if err else '200',
'body': res,
'headers': {
'Content-Type': 'image/png',
},
'isBase64Encoded': 'true'
}
Любые указатели на то, что я делаю не так?
Ответы
Ответ 1
Выполнение всех описанных выше шагов не сработало в моем случае, потому что двоичная поддержка content-type = */*
преобразует все ответы в двоичные.
Мой случай:
Несколько лямбда-функций, возвращающих json (текст), только одна лямбда-функция, возвращающая двоичный файл. У всех есть лямбда-прокси.
Лямбды находятся в шлюзе API
API-шлюз находится за CloudFront
Подсказка:
Я заметил важную информацию в API Gateway → Настройки
Цитирование:
API Gateway рассмотрит Content-Type и Accept HTTP-заголовки, чтобы решить, как обрабатывать тело.
Это означает, что заголовок ответа Content-Type должен соответствовать заголовку запроса request header
Решение:
Установите двоичные типы носителей в API-шлюзе на тип mime: image/jpg
В вашем HTTP-запросе установите Accept: image/jpg
В вашем HTTP-ответе установлено Content-Type: image/jpg
{
"isBase64Encoded": True,
"statusCode": 200,
"headers": { "content-type": "image/jpg"},
"body": base64.b64encode(content_bytes).decode("utf-8")
}
- Затем мы должны указать CloudFront принять заголовок "Accept" из запроса. Итак, в дистрибутиве CloudFront нажмите на свой экземпляр API Gateway (ID кликабелен) и после перенаправления на экземпляр CloudFront перейдите на вкладку Поведение, выберите шаблон пути вашего API (пример: /api/*) и нажмите кнопку Изменить.
На новом экране необходимо добавить заголовок Accept в белый список.
Примечание 1. Если у вас несколько типов файлов, вы должны добавить их все в двоичные типы носителей в настройках шлюза API
Примечание 2: Если вы пришли из без сервера и хотите установить типы двоичных файлов при развертывании лямбда файлов, проверьте этот пост: настройка двоичных типов мультимедиа для шлюза API
plugins:
- serverless-apigw-binary
custom:
apigwBinary:
types:
- 'image/jpeg'
Файл serverless.yml для облачного фронта должен содержать:
resources:
WebAppCloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
...
CacheBehaviors:
...
-
#API calls
...
ForwardedValues:
...
Headers:
- Authorization
- Accept
Ответ 2
Я, наконец, понял это. Возвращаемые двоичные данные из lambda python выполняются.
Следуйте инструкциям здесь: https://aws.amazon.com/blogs/compute/binary-support-for-api-integrations-with-amazon-api-gateway/
Обязательно проверьте "Использовать интеграцию прокси-сервера Lambda" при создании нового метода.
Также убедитесь, что ваш ответ на лямбду python выглядит так:
return {'isBase64Encoded' : True,
'statusCode' : 200,
'headers' : { 'Content-Type': content_type },
'body' : base64_encoded_binary_data}
ЗАТЕМ:
Для каждого из ваших маршрутов/методов:
apigateway update-integration-response --rest-api-id <api-id> --resource-id <res-id> --http-method POST --status-code 200 --patch-operations "[{\"op\" : \"replace\", \"path\" : \"/contentHandling\", \"value\" : \"CONVERT_TO_BINARY\"}]"
В консоли AWS. Их можно увидеть в "панировочных судах" API Gateway:
<api-id> = zdb7jsoey8
<res-id> = zy2b5g
THEN: вам нужно "Развернуть API". Из того, что я нашел, он работал только после развертывания API.
Перед развертыванием убедитесь, что вы установили "Бинарные типы носителей".
Подсказка: Nice терминал AWS оболочки здесь: https://github.com/awslabs/aws-shell
pip install aws-shell
Ответ 3
Насколько я могу судить, это также относится и к Python 3. Я пытаюсь вернуть двоичные данные (байты). Это не работает вообще.
Я также пытался использовать кодировку base-64, но у меня ничего не получилось.
Это с помощью API Gateway и Proxy Integration.
[Обновить]
Я наконец понял, как это сделать. Я включил двоичную поддержку для типа */*
а затем вернул это:
return({
"isBase64Encoded": True,
"statusCode": 200,
"headers": {
"content-type": "image/jpg",
},
'body': base64.b64encode(open('image.jpg', 'rb').read()).decode('utf-8')
})
Ответ 4
Я столкнулся с той же проблемой около 6 месяцев назад. Похоже, хотя в API Gateway теперь есть двоичная поддержка (и примеры в JS), Python 2.7 Lambda все еще не поддерживает корректный двоичный ответ, не уверен в Python 3.6.
У кодированного ответа Base64 возникают проблемы из-за упаковки JSON. Я написал пользовательскую JS на стороне клиента, снимая изображение базы 64 из этого JSON вручную, но это было также плохое решение.
Загрузите результат на S3 (за CloudFront) и верните 301 в CloudFront, кажется, хорошим решением. Работает лучше всего для меня.