@adobe/helix-fetch

中文文档
3.1.2发布于 2022/08/07Apache-2.0TypeScriptESM + CJS近 30 天下载 4368

Light-weight Fetch implementation transparently supporting both HTTP/1(.1) and HTTP/2

此软件包已被标记为弃用

WARNING: This project has been renamed to @adobe/fetch. Install using @adobe/fetch instead.

原始使用文档
文档目录34 节
  1. About
  2. Features
  3. Installation
  4. Upgrading
  5. API
  6. Context
  7. Common Usage Examples
  8. Access Response Headers and other Meta data
  9. Fetch JSON
  10. Fetch text data
  11. Fetch binary data
  12. Specify a timeout for a fetch operation
  13. Stream an image
  14. Post JSON
  15. Post JPEG image
  16. Post form data
  17. GET with query parameters object
  18. Cache
  19. Advanced Usage Examples
  20. HTTP/2 Server Push
  21. Force HTTP/1(.1) protocol
  22. HTTP/1.1 Keep-Alive
  23. Self-signed Certificates
  24. Set cache size limit
  25. Disable caching
  26. Set a custom user agent
  27. More examples
  28. Development
  29. Build
  30. Test
  31. Lint
  32. Troubleshooting
  33. Acknowledgement
  34. License
Helix Fetch

Light-weight Fetch API implementation transparently supporting both HTTP/1(.1) and HTTP/2

codecov CircleCI GitHub license GitHub issues LGTM Code Quality Grade: JavaScript Renovate enabled semantic-release Install size Current version


About

helix-fetch in general adheres to the Fetch API Specification, implementing a subset of the API. However, there are some notable deviations:

  • Response.body returns a Node.js Readable stream.
  • Response.blob() is not implemented. Use Response.buffer() instead.
  • Response.formData() is not implemented.
  • Cookies are not stored by default. However, cookies can be extracted and passed by manipulating request and response headers.
  • The following values of the fetch() option cache are supported: 'default' (the implicit default) and 'no-store'. All other values are currently ignored.
  • The following fetch() options are ignored due to the nature of Node.js and since helix-fetch doesn't have the concept of web pages: mode, referrer, referrerPolicy, integrity and credentials.
  • The fetch() option keepalive is not supported. But you can use the h1.keepAlive context option, as demonstrated here.

helix-fetch also supports the following extensions:

  • Response.buffer() returns a Node.js Buffer.
  • Response.url contains the final url when following redirects.
  • The body that can be sent in a Request can also be a Readable Node.js stream, a Buffer, a string or a plain object.
  • There are no forbidden header names.
  • The Response object has an extra property httpVersion which is one of '1.0', '1.1' or '2.0', depending on what was negotiated with the server.
  • The Response object has an extra property fromCache which determines whether the response was retrieved from cache.
  • The Response object has an extra property decoded which determines whether the response body was automatically decoded (see Fetch option decode below).
  • Response.headers.plain() returns the headers as a plain object.
  • The Fetch option follow allows to limit the number of redirects to follow (default: 20).
  • The Fetch option compress enables transparent gzip/deflate/br content encoding (default: true).
  • The Fetch option decode enables transparent gzip/deflate/br content decoding (default: true).

Note that non-standard Fetch options have been aligned with node-fetch where appropriate.

Features

  • supports reasonable subset of the standard Fetch specification
  • Transparent handling of HTTP/1(.1) and HTTP/2 connections
  • RFC 7234 compliant cache
  • Support gzip/deflate/br content encoding
  • HTTP/2 request and response multiplexing support
  • HTTP/2 Server Push support (transparent caching and explicit listener support)
  • overridable User-Agent
  • low-level HTTP/1.* agent/connect options support (e.g. keepAlive, rejectUnauthorized)

Installation

Note:

As of v2 Node version >= 12 is required.

$ npm install @adobe/helix-fetch

Upgrading

Upgrading from an old version of helix-fetch? Check out the following files:

API

Apart from the standard Fetch API

  • fetch()
  • Request
  • Response
  • Headers
  • Body

helix-fetch exposes the following extensions:

  • context() - creates a new customized API context
  • reset() - resets the current API context, i.e. closes pending sessions/sockets, clears internal caches, etc ...
  • onPush() - registers an HTTP/2 Server Push listener
  • offPush()- deregisters a listener previously registered with onPush()
  • clearCache() - clears the HTTP cache (cached responses)
  • cacheStats() - returns cache statistics
  • noCache() - creates a customized API context with disabled caching (convenience)
  • h1() - creates a customized API context with enforced HTTP/1.1 protocol (convenience)
  • keepAlive() - creates a customized API context with enforced HTTP/1.1 protocol and persistent connections (convenience)
  • h1NoCache() - creates a customized API context with disabled caching and enforced HTTP/1.1 protocol (convenience)
  • keepAliveNoCache() - creates a customized API context with disabled caching and enforced HTTP/1.1 protocol with persistent connections (convenience)
  • createUrl() - creates a URL with query parameters (convenience)
  • timeoutSignal() - ceates a timeout signal (convenience)

Context

An API context allows to customize certain aspects of the implementation and provides isolation of internal structures (session caches, HTTP cache, etc.) per API context.

The following options are supported:

interface ContextOptions {
  /**
   * Value of `user-agent` request header
   * @default 'helix-fetch/<version>'
   */
  userAgent?: string;
  /**
   * The maximum total size of the cached entries (in bytes). 0 disables caching.
   * @default 100 * 1024 * 1024
   */
  maxCacheSize?: number;
  /**
   * The protocols to be negotiated, in order of preference
   * @default [ALPN_HTTP2, ALPN_HTTP1_1, ALPN_HTTP1_0]
   */
  alpnProtocols?: ReadonlyArray< ALPNProtocol >;
  /**
   * How long (in milliseconds) should ALPN information be cached for a given host?
   * @default 60 * 60 * 1000
   */
  alpnCacheTTL?: number;
  /**
   * (HTTPS only, applies to HTTP/1.x and HTTP/2)
   * If not false, the server certificate is verified against the list of supplied CAs. An 'error' event is emitted if verification fails; err.code contains the OpenSSL error code.
   * @default true
   */
  rejectUnauthorized?: boolean;
  /**
   * Maximum number of ALPN cache entries
   * @default 100
   */
  alpnCacheSize?: number;
  h1?: Http1Options;
  h2?: Http2Options;
};

interface Http1Options {
  /**
   * Keep sockets around in a pool to be used by other requests in the future.
   * @default false
   */
  keepAlive?: boolean;
  /**
   * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive.
   * Only relevant if keepAlive is set to true.
   * @default 1000
   */
  keepAliveMsecs?: number;
  /**
   * (HTTPS only)
   * If not false, the server certificate is verified against the list of supplied CAs. An 'error' event is emitted if verification fails; err.code contains the OpenSSL error code.
   * @default true
   */
  rejectUnauthorized?: boolean;
  /**
   * (HTTPS only)
   * Maximum number of TLS cached sessions. Use 0 to disable TLS session caching.
   * @default 100
   */
  maxCachedSessions?: number;
}

interface Http2Options {
  /**
   * Max idle time in milliseconds after which a session will be automatically closed. 
   * @default 5 * 60 * 1000
   */
  idleSessionTimeout?: number;
  /**
   * Enable HTTP/2 Server Push?
   * @default true
   */
  enablePush?: boolean;
  /**
   * Max idle time in milliseconds after which a pushed stream will be automatically closed. 
   * @default 5000
   */
  pushedStreamIdleTimeout?: number;
  /**
   * (HTTPS only)
   * If not false, the server certificate is verified against the list of supplied CAs. An 'error' event is emitted if verification fails; err.code contains the OpenSSL error code.
   * @default true
   */
  rejectUnauthorized?: boolean;
};

Common Usage Examples

Access Response Headers and other Meta data

  const { fetch } = require('@adobe/helix-fetch');

  const resp = await fetch('https://httpbin.org/get');
  console.log(resp.ok);
  console.log(resp.status);
  console.log(resp.statusText);
  console.log(resp.httpVersion);
  console.log(resp.headers.plain());
  console.log(resp.headers.get('content-type'));

Fetch JSON

  const { fetch } = require('@adobe/helix-fetch');

  const resp = await fetch('https://httpbin.org/json');
  const jsonData = await resp.json();

Fetch text data

  const { fetch } = require('@adobe/helix-fetch');

  const resp = await fetch('https://httpbin.org/');
  const textData = await resp.text();

Fetch binary data

  const { fetch } = require('@adobe/helix-fetch');

  const resp = await fetch('https://httpbin.org//stream-bytes/65535');
  const imageData = await resp.buffer();

Specify a timeout for a fetch operation

Using timeoutSignal(ms) extension:

  const { fetch, timeoutSignal, AbortError } = require('@adobe/helix-fetch');

  const signal = timeoutSignal(1000);
  try {
    const resp = await fetch('https://httpbin.org/json', { signal });
    const jsonData = await resp.json();
  } catch (err) {
    if (err instanceof AbortError) {
      console.log('fetch timed out after 1s');
    }
  } finally {
    // avoid pending timers which prevent node process from exiting
    signal.clear();
  }

Using AbortController:

  const { fetch, AbortController, AbortError } = require('@adobe/helix-fetch');

  const controller = new AbortController();
  const timerId = setTimeout(() => controller.abort(), 1000);
  const { signal } = controller;

  try {
    const resp = await fetch('https://httpbin.org/json', { signal });
    const jsonData = await resp.json();
  } catch (err) {
    if (err instanceof AbortError) {
      console.log('fetch timed out after 1s');
    }
  } finally {
    // avoid pending timers which prevent node process from exiting
    clearTimeout(timerId);
  }

Stream an image

  const fs = require('fs');
  const { fetch } = require('@adobe/helix-fetch');

  const resp = await fetch('https://httpbin.org/image/jpeg');
  resp.body.pipe(fs.createWriteStream('saved-image.jpg'));

Post JSON

  const { fetch } = require('@adobe/helix-fetch');

  const method = 'POST';
  const body = { foo: 'bar' };
  const resp = await fetch('https://httpbin.org/post', { method, body });

Post JPEG image

  const fs = require('fs');
  const { fetch } = require('@adobe/helix-fetch');

  const method = 'POST';
  const body = fs.createReadStream('some-image.jpg');
  const headers = { 'content-type': 'image/jpeg' };
  const resp = await fetch('https://httpbin.org/post', { method, body, headers });

Post form data

  const { FormData, Blob, File } = require('formdata-node'); // spec-compliant implementations
  const { fileFromPath } = require('formdata-node/file-from-path'); // helper for creating File instance from disk file

  const { fetch } = require('@adobe/helix-fetch');

  const method = 'POST';
  const fd = new FormData();
  fd.set('field1', 'foo');
  fd.set('field2', 'bar');
  fd.set('blob', new Blob([0x68, 0x65, 0x6c, 0x69, 0x78, 0x2d, 0x66, 0x65, 0x74, 0x63, 0x68]));
  fd.set('file', new File(['File content goes here'], 'file.txt'));
  fd.set('other_file', await fileFromPath('/foo/bar.jpg', 'bar.jpg', { type: 'image/jpeg' }));
  const resp = await fetch('https://httpbin.org/post', { method, body: fd });

GET with query parameters object

const { createUrl, fetch } = require('@adobe/helix-fetch');

const qs = {
  helix: 'dummy',
  foo: 'bar',
  rumple: "stiltskin",
};

const resp = await fetch(createUrl('https://httpbin.org/json', qs));

or using URLSearchParams:

const { fetch } = require('@adobe/helix-fetch');

const body = new URLSearchParams({
  helix: 'dummy',
  foo: 'bar',
  rumple: "stiltskin",
});

const resp = await fetch('https://httpbin.org/json', { body });

Cache

Responses of GET and HEAD requests are by default cached, according to the rules of RFC 7234:

const { fetch } = require('@adobe/helix-fetch');

const url = 'https://httpbin.org/cache/60'; // -> max-age=60 (seconds)
// send initial request, priming cache
let resp = await fetch(url);
assert(resp.ok);
assert(!resp.fromCache);

// re-send request and verify it's served from cache
resp = await fetch(url);
assert(resp.ok);
assert(resp.fromCache);

You can disable caching per request with the cache: 'no-store' option:

const { fetch } = require('@adobe/helix-fetch');

const resp = await fetch('https://httbin.org/', { cache: 'no-store' });
assert(resp.ok);
assert(!resp.fromCache);

You can disable caching entirely:

const { fetch } = require('@adobe/helix-fetch').noCache();

Advanced Usage Examples

HTTP/2 Server Push

Note that pushed resources will be automatically and transparently added to the cache. You can however add a listener which will be notified on every pushed (and cached) resource.

  const { fetch, onPush } = require('@adobe/helix-fetch');

  onPush((url, response) => console.log(`received server push: ${url} status ${response.status}`));

  const resp = await fetch('https://nghttp2.org');
  console.log(`Http version: ${resp.httpVersion}`);

Force HTTP/1(.1) protocol

  const { fetch } = require('@adobe/helix-fetch').h1();

  const resp = await fetch('https://nghttp2.org');
  console.log(`Http version: ${resp.httpVersion}`);

HTTP/1.1 Keep-Alive

const { fetch } = require('@adobe/helix-fetch').keepAlive();

const resp = await fetch('https://httpbin.org/status/200');
console.log(`Connection: ${resp.headers.get('connection')}`); // -> keep-alive

Self-signed Certificates

const { fetch } = require('@adobe/helix-fetch').context({ rejectUnauthorized: false });

const resp = await fetch('https://localhost:8443/');  // a server using a self-signed certificate

Set cache size limit

  const { fetch, cacheStats } = require('@adobe/helix-fetch').context({
    maxCacheSize: 100 * 1024, // 100kb (Default: 100mb)
  });

  let resp = await fetch('https://httpbin.org/bytes/60000'); // ~60kb response
  resp = await fetch('https://httpbin.org/bytes/50000'); // ~50kb response
  console.log(cacheStats());

Disable caching

  const { fetch } = require('@adobe/helix-fetch').noCache();

  let resp = await fetch('https://httpbin.org/cache/60'); // -> max-age=60 (seconds)
  // re-fetch
  resp = await fetch('https://httpbin.org/cache/60');
  assert(!resp.fromCache);

Set a custom user agent

  const { fetch } = require('@adobe/helix-fetch').context({
    userAgent: 'custom-fetch'
  });

  const resp = await fetch('https://httpbin.org//user-agent');
  const json = await resp.json();
  console.log(json['user-agent']);

More examples

More example code can be found in the test source files.

Development

Build

$ npm install

Test

$ npm test

Lint

$ npm run lint

Troubleshooting

You can enable helix-fetch low-level debug console output by setting the DEBUG environment variable to helix-fetch*, e.g.:

$ DEBUG=helix-fetch* node test.js

This will produce console outout similar to:

  ...
  helix-fetch:core established TLS connection: #48 (www.nghttp2.org) +2s
  helix-fetch:core www.nghttp2.org -> h2 +0ms
  helix-fetch:h2 reusing socket #48 (www.nghttp2.org) +2s
  helix-fetch:h2 GET www.nghttp2.org/httpbin/user-agent +0ms
  helix-fetch:h2 session https://www.nghttp2.org established +1ms
  helix-fetch:h2 caching session https://www.nghttp2.org +0ms
  helix-fetch:h2 session https://www.nghttp2.org remoteSettings: {"headerTableSize":8192,"enablePush":true,"initialWindowSize":1048576,"maxFrameSize":16384,"maxConcurrentStreams":100,"maxHeaderListSize":4294967295,"maxHeaderSize":4294967295,"enableConnectProtocol":true} +263ms
  helix-fetch:h2 session https://www.nghttp2.org localSettings: {"headerTableSize":4096,"enablePush":true,"initialWindowSize":65535,"maxFrameSize":16384,"maxConcurrentStreams":4294967295,"maxHeaderListSize":4294967295,"maxHeaderSize":4294967295,"enableConnectProtocol":false} +0ms
  helix-fetch:h2 session https://www.nghttp2.org closed +6ms
  helix-fetch:h2 discarding cached session https://www.nghttp2.org +0ms
  ... 

Additionally, you can enable Node.js low-level debug console output by setting the NODE_DEBUG environment variable appropriately, e.g.

$ export NODE_DEBUG=http*,stream*
$ export DEBUG=helix-fetch*

$ node test.js

Note: this will flood the console with highly verbose debug output.

Acknowledgement

Thanks to node-fetch and github/fetch for providing a solid implementation reference.

License

Apache 2.0

版本与发布记录

@adobe/helix-fetch 共发布 51 个版本,首次发布于 2020/02/01;过去 12 个月发布了 0 个版本。

版本发布日期距今
3.1.2latest2022/08/074 年前
3.1.12022/06/304 年前
3.1.02022/06/294 年前
3.0.112022/06/164 年前
3.0.102022/05/144 年前
3.0.92022/04/104 年前

关于 @adobe/helix-fetch 的常见问题

@adobe/helix-fetch 是什么?

Light-weight Fetch implementation transparently supporting both HTTP/1(.1) and HTTP/2注意:该包已被作者标记为弃用——WARNING: This project has been renamed to @adobe/fetch. Install using @adobe/fetch instead.

如何安装 @adobe/helix-fetch?

在项目目录运行 npm install @adobe/helix-fetch,或使用 pnpm add / yarn add / bun add。

@adobe/helix-fetch 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adobe/helix-fetch 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@adobe/helix-fetch 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@adobe/helix-fetch 可以商用吗?

@adobe/helix-fetch 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@adobe/helix-fetch 的下载量有多少?

根据 npm 官方下载统计,@adobe/helix-fetch 在 2026/10/05 – 2026/11/03 这 30 天内被下载 4,368 次,日均约 146 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adobe/helix-fetch 还在维护吗?

最新版本 3.1.2 发布于 2022/08/07(4 年前);至今共发布 51 个版本,其中过去 12 个月发布了 0 个;首次发布于 2020/02/01。作者已将其标记为弃用,新项目建议寻找替代方案。