压缩

现行标准 — 最后更新

参与方式:
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. 支持的格式

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 字段存在且错误,则为错误。

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

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

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

  • 一个 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. 如果 formatCompressionStream 中不被支持,则抛出 TypeError

  2. thisformat 设为 format

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

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

  5. thistransform 设为一个 新的 TransformStream

  6. 使用 transformAlgorithm 设置为 transformAlgorithm flushAlgorithm 设置为 flushAlgorithm 初始化/设置 thistransform

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

  2. buffer 为使用 csformatcontext 压缩 chunk 的结果。

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

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

  5. 对于 arrays 中的每一个 Uint8Array array, 在 cstransformenqueue(入队) array

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

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

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

  4. 对于 arrays 中的每一个 Uint8Array array, 在 cstransformenqueue(入队) array

5. 接口 DecompressionStream

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

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

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

  2. thisformat 设为 format

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

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

  5. thistransform 设为一个 新的 TransformStream

  6. 使用 transformAlgorithm 设置为 transformAlgorithm flushAlgorithm 设置为 flushAlgorithm初始化/设置 thistransform

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

  2. buffer 为使用 dsformatcontext 解压 chunk 的结果。如果出错,则抛出 TypeError

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

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

  5. 对于 arrays 中的每一个 Uint8Array array, 在 dstransformenqueue(入队) array

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

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

  2. 如果 buffer 不为空:

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

    2. 对于 arrays 中的每一个 Uint8Array array, 在 dstransformenqueue(入队) 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+