Распаковка данных, полученных в виде двоичных данных в лямбде - неправильная проверка заголовка

Я хочу отправить сжатые данные (gzip) на некоторый URL-адрес, который вызовет лямбда-функцию (прокси), которая распаковывает данные.

Лямбда-функция (NodeJS 8):

let zlib = require('zlib');
exports.handler = async (event) => {
    let decompressedData = zlib.gunzipSync(event['body'])
    return {
        "statusCode": 200,
        "body": decompressedData.toString()
    };
};

Я запускаю его с помощью команды curl для URL-адреса (через API-шлюз) для некоторого файла, который я сжал example.gz с помощью gzip:

curl -X POST --data-binary @example.gz https://URL...

В результате получаю:

{"message": "Internal server error"}

И ошибка (логи в Cloudwatch):

   "errorMessage": "incorrect header check",
    "errorType": "Error",
    "stackTrace": [
        "Gunzip.zlibOnError (zlib.js:153:15)",
        "Gunzip._processChunk (zlib.js:411:30)",
        "zlibBufferSync (zlib.js:144:38)",
        "Object.gunzipSync (zlib.js:590:14)",
        "exports.handler (/var/task/test_index.js:5:33)"
    ]

Когда я смотрю на сам event['body'], я вижу те же данные, что и в example.gz. Возможно, мне нужен какой-то специальный заголовок? Я просто хочу передать данные как есть.

Пожалуйста, разместите тело события

Rajarshi Das 10.04.2019 14:04

По умолчанию API Gateway не может передавать двоичные данные в функцию Lambda event['body'] без их повреждения, поскольку это двоичные данные, а event['body'] — это строка, передаваемая Lambda в формате JSON. Его нужно будет завернуть в base-64. Ваша строка может выглядеть так же, но она почти наверняка не будет идентична байт за байтом после того, как попадет в лямбда-функцию. docs.aws.amazon.com/apigateway/latest/developerguide/…

Michael - sqlbot 10.04.2019 22:46

@Michael-sqlbot Спасибо! Пожалуйста, добавьте свой комментарий в качестве ответа, чтобы я мог хотя бы вознаградить вас за то, что вы направили меня к решению. Во всяком случае, я добавил свой ответ.

sheldonzy 12.04.2019 17:31

@sheldonzy спасибо за предложение, но ваш ответ очень хорош. Я указал вам правильное направление, но вы побежали с ним и решили его, так что +1 от меня. Я не обижусь, если вы отметите свой ответ как принятый ответ.

Michael - sqlbot 13.04.2019 03:05
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
1 396
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

1/ Сначала вам нужно правильно собрать gzip, убедитесь, что заголовок файла gzip отсутствует: Команда curl отправляет сжатое тело POST на сервер apache.

Неправильный способ :

echo '{ "mydummy" : "json" }' > body
gzip body
hexdump -C body.gz
00000000  1f 8b 08 08 20 08 30 59  00 03 62 6f 64 79 00 ab  |.... .0Y..body..|
00000010  56 50 ca ad 4c 29 cd cd  ad 54 52 b0 52 50 ca 2a  |VP..L)...TR.RP.*|
00000020  ce cf 53 52 a8 e5 02 00  a6 6a 24 99 17 00 00 00  |..SR.....j$.....|
00000030

Хороший способ :

echo '{ "mydummy" : "json" }' | gzip > body.gz
hexdump -C body.gz
00000000  1f 8b 08 00 08 0a 30 59  00 03 ab 56 50 ca ad 4c  |......0Y...VP..L|
00000010  29 cd cd ad 54 52 b0 52  50 ca 2a ce cf 53 52 a8  |)...TR.RP.*..SR.|
00000020  e5 02 00 a6 6a 24 99 17  00 00 00                 |....j$.....|
0000002b

2/ В curl не забудьте указать кодировку содержимого с помощью

-H "Content-Encoding: gzip"

3/Кроме того, если вы используете экспресс+сжатие, вам не нужно вызывать zlib

 curl -X POST "http://example.org/api/a" -H "Content-Encoding: gzip" -H "Content-Type: application/json" --data-binary @body.gz

router.post("/api/a", function(req, res){
    console.info(req.body); // { mydummy: 'json' }
});

На самом деле я сейчас делаю это с Content-Encoding: gzip, но это так медленно, что я хочу попробовать распаковать в самой лямбде.

sheldonzy 10.04.2019 14:24
Ответ принят как подходящий

как сказал Майкл - sqlbot, по умолчанию шлюз API не может передавать двоичные данные в функцию Lambda.

Что сработало для меня: Я добавил заголовок Content-Type: application/octet-stream в команду curl, а в настройках API-шлюза на Binary Media Types добавил application/octet-stream.

Таким образом, данные передаются в формате base64, а затем я просто преобразовал дату в формате base64 в буфер:

let data = Buffer.from(event['body'], "base64")

А потом просто распаковать.

Для получения дополнительной информации читать здесь

Другие вопросы по теме