Извлечение данных gzip в Javascript с помощью Pako - проблемы с кодировкой

Я пытаюсь запустить то, что я ожидаю, это очень распространенный вариант использования:

Мне нужно загрузить файл gzip (из сложных наборов данных JSON) из Amazon S3 и распаковать его (gunzip) в Javascript. У меня все работает правильно, кроме последнего шага "надувать".

Я использую Amazon Gateway и подтвердил, что шлюз правильно передает сжатый файл (для проверки получаемых данных из API используются Curl и 7-zip). К сожалению, когда я пытаюсь надуть данные в Javascript с помощью Pako, я получаю ошибки.

Вот мой код (примечание: response.data - это двоичные данные, передаваемые из AWS):

apigClient.dataGet(params, {}, {})
      .then( (response) => {
        console.log(response);  //shows response including header and data

        const result = pako.inflate(new Uint8Array(response.data), { to: 'string' });
        // ERROR HERE: 'buffer error'  

      }).catch ( (itemGetError) => {
        console.log(itemGetError);
      });

Также попробовал версию, чтобы сделать это, разбивая вход двоичных данных в массив, добавляя следующее перед инфляцией:

const charData = response.data.split('').map(function(x){return x.charCodeAt(0); });
const binData = new Uint8Array(charData);
const result = pako.inflate(binData, { to: 'string' });
//ERROR: incorrect header check

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

Кто-нибудь может указать мне правильное направление, чтобы заставить это работать?

Для ясности:

  • Поскольку приведенный выше код указан, я получаю ошибку буфера. Если я отбрасываю Uint8Array и просто пытаюсь обработать "result.data", я получаю ошибку: "проверка некорректного заголовка", из-за чего я подозреваю, что проблема заключается в кодировании / формате моих данных.
  • Исходный файл был сжат в Java с использованием GZIPOutputStream с UTF-8, а затем сохранен в виде статического файла (то есть randomname.gz).

  • Файл передается через шлюз AWS как двоичный файл, поэтому он точно такой же, как и исходный файл, поэтому 'curl --output filename.gz {URLtoS3Gateway}' === загруженный файл из S3.

  • У меня была та же базовая проблема, когда я использовал шлюз для кодирования двоичных данных как "base64", но я не очень старался из-за этих усилий, так как кажется, что легче работать с "настоящими" двоичными данными, чем добавлять base64 кодировать / декодировать в середине. Если это необходимый шаг, я могу добавить его обратно.

Я также попробовал некоторые примеры обработки, найденные на полпути через эту проблему: https://github.com/nodeca/pako/issues/15, но это не помогло (возможно, я неправильно понял двоичный формат v. Массив v base64).

1 ответ

Решение

Я смог выяснить свою проблему. Это было связано с форматом данных, читаемых Javascript (либо самим Javascript, либо реализацией Angular HttpClient). Я читал в "двоичном" формате, но он не был таким же, как тот, который распознал / использовал Пако. Когда я прочитал данные как base64, а затем преобразовал их в двоичный файл с помощью 'atob', я смог заставить его работать. Вот что я на самом деле реализовал (начиная с выборки из хранилища файлов S3).

1) Создайте AWS API Gateway, который будет считывать ранее сохраненный файл *.gz с S3.

  • Создайте стандартный запрос get "get" к S3, который поддерживает двоичный файл. ( http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings-configure-with-console.html)
  • Убедитесь, что шлюз распознает тип ввода, установив "Бинарные типы" (application/ gzip работал для меня, но другие, такие как application/ binary-octet и image / png, должны работать для других типов файлов, кроме *.gz). ПРИМЕЧАНИЕ. Этот параметр находится в главном списке выбора API в левой части экрана настройки API.
  • Установите для параметра "Обработка содержимого" значение "Преобразовать в текст (если необходимо)", выбрав "Метод API" / "GET} -> Блок запроса интеграции и обновив элемент" Обработка содержимого ". (ПРИМЕЧАНИЕ: пример в приведенной выше ссылке рекомендует "passthrough". НЕ используйте его, поскольку он пропустит нечитаемый двоичный формат.) Это шаг, который фактически преобразуется из двоичного в base64.

На этом этапе вы сможете загрузить версию своего двоичного файла в формате base64 через URL (тест в браузере или с помощью Curl).

2) Затем API-шлюз сгенерировал SDK и использовал соответствующий вызов apiGClient.{Get}.

3) Внутри вызова, переведите base64->binary->Uint8, а затем распакуйте / надуйте его. Мой код для этого:

    apigClient.myDataGet(params, {}, {})
      .then( (response) => {
        // HttpClient result is in response.data
        // convert the incoming base64 -> binary
        const strData = atob(response.data);

        // split it into an array rather than a "string"
        const charData = strData.split('').map(function(x){return x.charCodeAt(0); });

        // convert to binary
        const binData = new Uint8Array(charData);

        // inflate
        const result = pako.inflate(binData, { to: 'string' });
        console.log(result);
      }).catch ( (itemGetError) => {
        console.log(itemGetError);
      });
  }
Другие вопросы по тегам