使用 Pako 在 Javascript 中提取 gzip 数据 - 编码问题

Extracting gzip data in Javascript with Pako - encoding issues

我正在尝试 运行 我期望的是一个非常常见的用例:

我需要从 Amazon S3 下载一个 gzip 文件(包含复杂的 JSON 数据集),并在 Java 脚本中解压缩(gunzip)它。除了最后的 'inflate' 步骤外,我的一切都正常工作。

我正在使用 Amazon Gateway,并已确认 Gateway 正在正确传输压缩文件(使用 Curl 和 7-zip 验证结果数据是否来自 API)。不幸的是,当我尝试使用 Pako 在 Java 脚本中扩充数据时,出现了错误。

这是我的代码(注: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);
      });

还尝试了一个版本,通过在 inflate 之前添加以下内容,将二进制数据输入拆分为数组:

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 有意义的正确格式。

任何人都可以为我指明正确的方向以使其正常工作吗?

为清楚起见:

我也尝试了一些在此问题中途发现的示例处理:https://github.com/nodeca/pako/issues/15,但这没有帮助(我可能误解了二进制格式 v. array v base64)。

我能够找出我自己的问题。它与 Javascript 读取的数据格式有关(Javascript 本身或 Angular HttpClient 实现)。我正在阅读 "binary" 格式,但它与 pako 的 recognized/used 不同。当我以 base64 格式读取数据,然后使用 'atob' 转换为二进制时,我能够让它工作。这是我实际实现的(从从 S3 文件存储中获取开始)。

1) 构建 AWS API 网关,它将从 S3 读取先前存储的 *.gz 文件。

  • 创建一个标准 "get" API 请求到支持二进制的 S3。 (http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings-configure-with-console.html)
  • 通过设置 'Binary types' 确保网关能够识别输入类型(application/gzip 对我有效,但 application/binary-octet 和 image/png 等其他类型应该适用于其他类型*.gz 之外的文件)。注意:该设置位于 API 配置屏幕左侧的主要 API 选择列表下。
  • 通过选择 API 方法/{GET} -> 集成请求框并更新 'Content Handling' 项目,将 'Content Handling' 设置为 "Convert to text(if needed)"。 (注意:上面 link 中的示例推荐 "passthrough"。不要使用它,因为它会传递不可读的二进制格式。)这是实际从二进制转换为 base64 的步骤。

此时您应该可以通过 URL 下载二进制文件的 base64 版本(在浏览器中或使用 Curl 进行测试)。

2) 然后我让 API 网关生成 SDK 并使用相应的 apiGClient.{get} 调用。

3) 在调用中,翻译 base64->binary->Uint8,然后 decompress/inflate 它。我的代码:

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