压缩

现行标准 — 最后更新

参与方式:
GitHub whatwg/compression (新建议题, 开放议题)
Matrix 聊天
提交记录:
GitHub whatwg/compression/commits
此提交快照
@compressionapi
测试:
web-platform-tests compression/ (正在进行的工作)
翻译 (非规范性):
简体中文
日本語
한국어

摘要

本文档定义了一组用于压缩和解压二进制数据流的 JavaScript API。

1. 简介

本节为非规范性内容。

本规范中定义的 API 用于对数据流进行压缩和解压。它们支持 "deflate"、"deflate-raw" 和 "gzip" 作为压缩算法,这些算法被网页开发者广泛使用。

2. 基础设施

本规范依赖于 Infra。[INFRA]

一个 chunk 是一段数据。对于 CompressionStream 和 DecompressionStream,输出 chunk 类型为 Uint8Array。它们接受任何 BufferSource 类型作为输入。

一个 stream 表示有序的 chunk 序列。ReadableStream 和 WritableStream 的术语定义在 Streams。[STREAMS]

压缩上下文 是压缩或解压算法维护的内部状态。压缩上下文 的内容取决于所用的格式、算法和实现。从本规范的角度来说,它是一个不透明对象。压缩上下文 初始处于起始状态,等待输入的第一个字节。

3. 支持的格式

brotli

"Brotli 压缩数据格式" [RFC7932]

deflate

"ZLIB 压缩数据格式" [RFC1950]

注意:为与 HTTP 内容编码保持一致,该格式称为 "deflate"。参见 [RFC7230] 第 4.2.2 节。

  • 实现必须如 [RFC1950] 第 2.3 节所述“兼容”。

  • [RFC1950] 描述为无效的字段值不得由 CompressionStream 生成, 并且对 DecompressionStream 来说是错误。

  • CMF 字段中的 CM(压缩方法)部分唯一有效的值为 8。

  • 这些 API 不支持 FDICT 标志,如果设置则会使流出错。

  • DecompressionStream 会忽略 FLEVEL 标志。

  • 若 ADLER32 校验和不正确,则对 DecompressionStream 来说是错误。

  • 如果在 ADLER32 校验和之后还有额外输入数据,则为错误。

deflate-raw

"DEFLATE 算法" [RFC1951]

  • 实现必须如 [RFC1951] 第 1.4 节所述“兼容”。

  • 由 CompressionStream 生成的块不得不符合 [RFC1951] 标准,否则对 DecompressionStream 来说是错误。

  • 如果在 BFINAL 标志指示的最后一个块之后还有额外输入数据,则为错误。

gzip

"GZIP 文件格式" [RFC1952]

  • 实现必须如 [RFC1952] 第 2.3.1.2 节所述“兼容”。

  • [RFC1952] 描述为无效的字段值不得由 CompressionStream 生成, 并且对 DecompressionStream 来说是错误。

  • CM(压缩方法)字段的唯一有效值为 8。

  • DecompressionStream 必须忽略 FTEXT 标志。

  • 如果 FHCRC 字段存在且错误,则为错误。

  • 任何 FEXTRA、FNAME 和 FCOMMENT 字段内容 除了要验证正确结束外,都必须由 DecompressionStream 忽略。

  • MTIME、XFL 和 OS 字段内容 必须由 DecompressionStream 忽略。

  • 如果 CRC32 或 ISIZE 与解压后的数据不匹配,则为错误。

  • 一个 gzip 流只可包含一个“成员”。

  • 如果在“成员”结尾后还有额外输入数据,则为错误。

4. 接口 CompressionStream

enum CompressionFormat {
  "brotli",
  "deflate",
  "deflate-raw",
  "gzip",
};

[Exposed=*]
interface CompressionStream {
  constructor(CompressionFormat format);
};
CompressionStream includes GenericTransformStream;

CompressionStream 具有关联的 format(格式) 和 compression context(压缩上下文) context(上下文)。

new CompressionStream(format) 步骤如下:
  1. 如果 format 在 CompressionStream 中不被支持,则抛出 TypeError 。

  2. 将 this 的 format 设为 format。

  3. 令 transformAlgorithm 是一个接收 chunk 参数的算法, 并使用 compress and enqueue a chunk 算法, 传入 this 和 chunk 执行。

  4. 令 flushAlgorithm 是一个不接收参数的算法, 并使用 compress flush and enqueue 算法, 传入 this 执行。

  5. 将 this 的 transform 设为一个 新的 TransformStream。

  6. 使用 transformAlgorithm 设置为 transformAlgorithm 及 flushAlgorithm 设置为 flushAlgorithm 初始化/设置 this 的 transform。

compress and enqueue a chunk(压缩并排队一个块) 算法,给定一个 CompressionStream 对象 cs 和一个 chunk,执行以下步骤:
  1. 如果 chunk 不是 BufferSource 类型,则抛出 TypeError 。

  2. 令 buffer 为使用 cs 的 format 和 context 压缩 chunk 的结果。

  3. 如果 buffer 为空,则返回。

  4. 令 arrays 为将 buffer 拆分为一个或多个非空片段并转换为 Uint8Array 的结果。

  5. 对于 arrays 中的每一个 Uint8Array array, 在 cs 的 transform 中 enqueue(入队) array。

compress flush and enqueue(压缩刷新并排队) 算法,用于处理输入 ReadableStream 对象流末端,给定一个 CompressionStream 对象 cs,执行以下步骤:
  1. 令 buffer 为用 cs 的 format 和 context,带 finish 标志压缩空输入的结果。

  2. 如果 buffer 为空,则返回。

  3. 令 arrays 为将 buffer 拆分为一个或多个非空片段并转换为 Uint8Array 的结果。

  4. 对于 arrays 中的每一个 Uint8Array array, 在 cs 的 transform 中 enqueue(入队) array。

5. 接口 DecompressionStream

[Exposed=*]
interface DecompressionStream {
  constructor(CompressionFormat format);
};
DecompressionStream includes GenericTransformStream;

DecompressionStream 具有关联的 format(格式) 和 compression context(压缩上下文) context(上下文)。

new DecompressionStream(format) 步骤如下:
  1. 如果 format 在 DecompressionStream 不被支持,则抛出 TypeError 。

  2. 将 this 的 format 设为 format。

  3. 令 transformAlgorithm 是一个接收 chunk 参数的算法, 并用 decompress and enqueue a chunk 算法, 传入 this 和 chunk 执行。

  4. 令 flushAlgorithm 是一个不接收参数的算法, 并用 decompress flush and enqueue 算法, 传入 this 执行。

  5. 将 this 的 transform 设为一个 新的 TransformStream。

  6. 使用 transformAlgorithm 设置为 transformAlgorithm 及 flushAlgorithm 设置为 flushAlgorithm, 初始化/设置 this 的 transform。

decompress and enqueue a chunk(解压并排队一个块) 算法,给定一个 DecompressionStream 对象 ds 和一个 chunk,执行以下步骤:
  1. 如果 chunk 不是 BufferSource 类型,则抛出 TypeError 。

  2. 令 buffer 为使用 ds 的 format 和 context 解压 chunk 的结果。如果出错,则抛出 TypeError。

  3. 如果 buffer 为空,则返回。

  4. 令 arrays 为将 buffer 拆分为一个或多个非空片段并转换为 Uint8Array 的结果。

  5. 对于 arrays 中的每一个 Uint8Array array, 在 ds 的 transform 中 enqueue(入队) array。

  6. 如果已到压缩输入末尾,但 ds 的 context 尚未完全消费 chunk,则抛出 TypeError。

decompress flush and enqueue(解压刷新并排队) 算法,用于处理输入 ReadableStream 对象流末端,给定一个 DecompressionStream 对象 ds,执行以下步骤:
  1. 令 buffer 为用 ds 的 format 和 context 并带 finish 标志解压空输入的结果。

  2. 如果 buffer 不为空:

    1. 令 arrays 为将 buffer 拆分为一个或多个非空片段并转换为 Uint8Array 的结果。

    2. 对于 arrays 中的每一个 Uint8Array array, 在 ds 的 transform 中 enqueue(入队) array。

  3. 如果未到压缩输入结尾,则抛出 TypeError。

6. 隐私与安全注意事项

该 API 不会为 Web 平台带来任何新的权限。

但是,网页开发者需要注意攻击者可能获得数据长度的情况。如果发生这种情况,攻击者可能能够猜测数据内容。

7. 示例

7.1. Gzip 压缩流

const compressedReadableStream
    = inputReadableStream.pipeThrough(new CompressionStream('gzip'));

7.2. Deflate 压缩 ArrayBuffer 到 Uint8Array

async function compressArrayBuffer(input) {
  const cs = new CompressionStream('deflate');

  const writer = cs.writable.getWriter();
  writer.write(input);
  writer.close();

  const output = [];
  let totalSize = 0;
  for (const chunk of cs.readable) {
    output.push(value);
    totalSize += value.byteLength;
  }

  const concatenated = new Uint8Array(totalSize);
  let offset = 0;
  for (const array of output) {
    concatenated.set(array, offset);
    offset += array.byteLength;
  }

  return concatenated;
}

7.3. Gzip 解压 Blob 到 Blob

function decompressBlob(blob) {
  const ds = new DecompressionStream('gzip');
  const decompressionStream = blob.stream().pipeThrough(ds);
  return new Response(decompressionStream).blob();
}

致谢

感谢 Canon Mukai、Domenic Denicola 和 Yutaka Hirano 的支持。

本标准由 Adam Rice (Google, ricea@chromium.org) 编写。

知识产权

本现行标准最初在 W3C WICG 开发,可根据 W3C 软件与文档许可证 获取。

版权所有 © WHATWG(Apple、Google、Mozilla、Microsoft)。本作品采用 知识共享署名 4.0 国际许可证 许可。在其部分内容被纳入源代码时,该部分在源代码中则采用 BSD 3-Clause 许可证 许可。

这是现行标准。希望查阅专利审查版本的请查看 现行标准审查草案。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性参考文献

[INFRA]
Anne van Kesteren;Domenic Denicola。Infra 标准。Living Standard。网址:https://infra.spec.whatwg.org/
[RFC1950]
P. Deutsch;J-L. Gailly。ZLIB 压缩数据格式 规范 3.3 版。1996年5月。信息性。网址:https://www.rfc-editor.org/rfc/rfc1950
[RFC1951]
P. Deutsch。DEFLATE 压缩数据格式 规范 1.3 版。1996年5月。信息性。网址:https://www.rfc-editor.org/rfc/rfc1951
[RFC1952]
P. Deutsch。GZIP 文件格式 规范 4.3 版。1996年5月。信息性。网址:https://www.rfc-editor.org/rfc/rfc1952
[RFC7932]
J. Alakuijala;Z. Szabadka。Brotli 压缩数据 格式。2016年7月。信息性。网址:https://www.rfc-editor.org/rfc/rfc7932
[STREAMS]
Adam Rice 等。Streams 标准。Living Standard。网址:https://streams.spec.whatwg.org/
[WEBIDL]
Edgar Chen;Timothy Gu。Web IDL 标准。Living Standard。网址:https://webidl.spec.whatwg.org/

非规范性参考文献

[RFC7230]
R. Fielding, Ed.;J. Reschke, Ed.。超文本传输协议(HTTP/1.1):消息语法与路由。2014年6月。建议标准。URL:https://httpwg.org/specs/rfc7230.html

IDL索引

enum CompressionFormat {
  "brotli",
  "deflate",
  "deflate-raw",
  "gzip",
};

[Exposed=*]
interface CompressionStream {
  constructor(CompressionFormat format);
};
CompressionStream includes GenericTransformStream;

[Exposed=*]
interface DecompressionStream {
  constructor(CompressionFormat format);
};
DecompressionStream includes GenericTransformStream;

✔MDN

CompressionStream/CompressionStream

In all current engines.

Firefox113+Safari16.4+Chrome80+
Opera?Edge80+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js17.0.0+
✔MDN

CompressionStream

In all current engines.

Firefox113+Safari16.4+Chrome80+
Opera?Edge80+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js18.0.0+
✔MDN

DecompressionStream/DecompressionStream

In all current engines.

Firefox113+Safari16.4+Chrome80+
Opera?Edge80+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js17.0.0+
✔MDN

DecompressionStream

In all current engines.

Firefox113+Safari16.4+Chrome80+
Opera?Edge80+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.js18.0.0+