浏览器 Javascript:将 Json 压缩为 gzip 并上传到 S3 预签名 URL

Tie*_*udt 5 javascript gzip amazon-s3 pako

任何意见,将不胜感激。我的 Web 应用程序中有一个 json 变量,我想对其进行 gzip 压缩并通过预签名 URL 上传到 S3。

我能够成功上传 JSON,但无法对 JSON 进行 gzip 压缩然后上传。

我尝试构建 gzipped json 的三种不同方法是:

// example json
const someJson = { testOne: 'a', testTwo: 'b' };

// Attempt one
const stringUtf16 = JSON.stringify(someJson);
const resultAsBinString = pako.gzip(stringUtf16);

// Attempt two
const stringUtf16 = JSON.stringify(someJson);
const resultAsBinString = pako.gzip(stringUtf16, { to: 'string' });

// Attempt three
const stringUtf16ThatWeNeedInUtf8 = JSON.stringify(someJson);
const stringUtf8 = unescape(encodeURIComponent(stringUtf16ThatWeNeedInUtf8));
const resultAsBinString = pako.gzip(stringUtf8);
Run Code Online (Sandbox Code Playgroud)

对于每次尝试,我都通过 Angular 的 HTTP 客户端上传 resultAsBinString,标头为 Content-Type: 'application/x-gzip' 和 Content-Encoding: 'gzip'

但是,当(并且经常出现网络错误)随后从 S3 下载文件时,尝试在终端中使用 gzip 或gunzip 解压缩时,会给出错误消息:“不是 gzip 格式”

我尝试遵循的来源:

https://github.com/nodeca/pako/issues/55 https://github.com/nodeca/pako/blob/master/examples/browser.html

Mic*_*bot 5

Content-Encoding: gzip如果您希望负载在下载后保持 gzip 状态,则设置不正确。当您希望浏览器透明地解码 gzip 编码时才使用此选项- 例如在提供 gzip 压缩的 HTML、JavaScript、CSS 等时。

如果Content-Encoding: gzip使用,则应Content-Type设置为与实际负载匹配,例如Content-Type: application/json

如果Content-Type: application/x-gzip使用,则Content-Encoding不应使用,除非您使用不同类型的压缩来重新压缩 gzip 有效负载(不太可能)。

Content-Type: application/x-gzip结合Content-Encoding: gzip意味着您已将 gzip 压缩文件包装在另一层 gzip 压缩中,并且您希望浏览器删除外层,这在实践中是不会做的。


Tie*_*udt 5

以下过程对我有用:

生成内容类型为“application/json”的预签名 URL。提供的文件名末尾应包含 .gz。在返回的预签名 URL 中,扫描 URL 应验证内容类型是否为 application/json。

因为我确信我的 JSON 不包含会破坏到 UTF-8 转换的字符串,所以我执行以下操作(Angular 中的代码,但它传达了结构):

const headers = new HttpHeaders({
    'Content-Type': 'application/json',
    'Content-Encoding': 'gzip'
});  //1
const httpOptions = {
    headers: headers
};
const str = JSON.stringify(geoJson); //2
const utf8Data = unescape(encodeURIComponent(str)); //3
const geoJsonGz = pako.gzip(utf8Data); //4
const gzippedBlob = new Blob([geoJsonGz]); //5
upload = this.httpClient.put(presignedUploadUrl, gzippedBlob, httpOptions); //6
Run Code Online (Sandbox Code Playgroud)

代码中遵循的步骤:

  1. Content Type 标头为 application/json,Content-Encoding 为 gzip。
  2. 将 JSON 字符串化
  3. 将字符串转换为 UTF-8
  4. 对字符串进行 Gzip 压缩
  5. 从压缩数据创建文件
  6. 将文件上传到预先指定的 URL

然后,您可以从 S3 下载 gzip 压缩文件(浏览器应自动解压缩该文件)并打开它以验证它是否包含相同的结果。