压缩

现行标准 — 最后更新

参与方式:
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 序列。ReadableStreamWritableStream 的术语定义在 Streams[STREAMS]

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

3. 支持的格式

deflate

“ZLIB 压缩数据格式”[RFC1950]

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

  • 实现必须遵循 [RFC1950] 第2.3节所述的“兼容性”。

  • CompressionStream 不得创建 [RFC1950] 中描述为无效的字段值,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节所述的“兼容性”。

  • CompressionStream 不得创建 [RFC1952] 中描述为无效的字段值,DecompressionStream 处理此类值时应报错。

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

  • DecompressionStream 必须忽略 FTEXT 标志。

  • FHCRC 字段存在且不正确,则会报错。

  • DecompressionStream 必须忽略 FEXTRAFNAMEFCOMMENT 字段的内容,仅需验证其正确结束。

  • DecompressionStream 必须忽略 MTIMEXFLOS 字段的内容。

  • CRC32ISIZE 与解压后的数据不匹配,则会报错。

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

  • 若“成员”结束后还有额外输入数据,则会报错。

4. 接口 CompressionStream

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

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

CompressionStream 拥有一个 格式 和一个 压缩上下文 上下文

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

  2. this格式设为 format

  3. transformAlgorithm 为一个接受 chunk 参数的算法,并使用 压缩并入队一个块 算法,传入 thischunk

  4. flushAlgorithm 为一个无参数的算法,并使用 压缩、刷新并入队 算法,传入 this

  5. thistransform 设为 新建TransformStream

  6. 设置 thistransform,其 transformAlgorithm 设为 transformAlgorithmflushAlgorithm 设为 flushAlgorithm

压缩并入队一个块 算法,给定 CompressionStream 对象 cschunk,执行以下步骤:
  1. 如果 chunk 不是 BufferSource 类型,则抛出 TypeError

  2. buffer 为使用 cs格式上下文 压缩 chunk 的结果。

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

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

  5. 对每个 Uint8Array array 属于 arrays入队 arraycstransform 中。

压缩、刷新并入队 算法,用于处理输入 ReadableStream 对象的数据结束,给定 CompressionStream 对象 cs,执行下列步骤:
  1. buffer 为使用 cs格式上下文 压缩空输入,并设置完成标志后的结果。

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

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

  4. 对每个 Uint8Array array 属于 arrays入队 arraycstransform 中。

5. 接口 DecompressionStream

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

DecompressionStream 拥有一个 格式 和一个 压缩上下文 上下文

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

  2. this格式设为 format

  3. transformAlgorithm 为一个接受 chunk 参数的算法,并使用 解压并入队一个块 算法,传入 thischunk

  4. flushAlgorithm 为一个无参数的算法,并使用 解压、刷新并入队 算法,传入 this

  5. thistransform 设为 新建TransformStream

  6. 设置 thistransform,其 transformAlgorithm 设为 transformAlgorithmflushAlgorithm 设为 flushAlgorithm

解压并入队一个块 算法,给定 DecompressionStream 对象 dschunk,执行以下步骤:
  1. 如果 chunk 不是 BufferSource 类型,则抛出 TypeError

  2. buffer 为使用 ds格式上下文 解压 chunk 的结果。如果产生错误,则抛出 TypeError

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

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

  5. 对每个 Uint8Array array 属于 arrays入队 arraydstransform 中。

解压、刷新并入队 算法,用于处理输入 ReadableStream 对象的数据结束,给定 DecompressionStream 对象 ds,执行下列步骤:
  1. buffer 为使用 ds格式上下文 解压空输入,并设置完成标志后的结果。

  2. 如果压缩输入的结尾尚未到达,则抛出 TypeError

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

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

  5. 对每个 Uint8Array array 属于 arrays入队 arraydstransform 中。

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标准。现行标准。URL:https://infra.spec.whatwg.org/
[RFC1950]
P. Deutsch;J-L. Gailly。ZLIB压缩数据格式规范3.3版。1996年5月。信息性。URL:https://www.rfc-editor.org/rfc/rfc1950
[RFC1951]
P. Deutsch。DEFLATE压缩数据格式规范1.3版。1996年5月。信息性。URL:https://www.rfc-editor.org/rfc/rfc1951
[RFC1952]
P. Deutsch。GZIP文件格式规范4.3版。1996年5月。信息性。URL:https://www.rfc-editor.org/rfc/rfc1952
[STREAMS]
Adam Rice 等。Streams标准。现行标准。URL:https://streams.spec.whatwg.org/
[WEBIDL]
Edgar Chen;Timothy Gu。Web IDL标准。现行标准。URL: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 {
  "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+