关于
helix-fetch 一般遵守 获取 API 规格,执行 API 的子集。 然而,有一些明显的偏差:
Response.body返回节点.js 可读流。 。 。 .Response.blob()未执行。 使用Response.buffer()换句话说.Response.formData()未执行.- 饼干不是默认保存的. 然而,饼干可以通过操纵请求和响应头来取出并传递.
- 以下数值
fetch()选项cache已支持:'default'和'no-store'。所有其他值目前都被忽略. - 以下内容:
fetch()由于Node.js的性质,自此,选项被忽略helix-fetch没有网页的概念:mode, (中文(简体) ),referrer, (中文(简体) ),referrerPolicy, (中文(简体) ),integrity财务报告和审定财务报表credentials。 。 。 . - 这个
fetch()选项keepalive不被支持。 但你可以使用这个h1.keepAlive显示的上下文选项 这里。 。 。 .
helix-fetch 还支持以下扩展:
Response.buffer()返回节点.jsBuffer。 。 。 .Response.url包含跟踪方向调整时的最后url.- 这个
body可以发送到Request也可以是一个Readable节点.js流, aBuffer、字符串或普通对象. - 没有禁用的标题.
- 这个
Response对象有额外的属性httpVersion这是其中之一'1.0', (中文(简体) ),'1.1'或者说'2.0',取决于与服务器谈判的内容. - 这个
Response对象有额外的属性fromCache它决定了是否从缓存中检索到答复. - 这个
Response对象有额外的属性decoded决定响应机构是否自动解码(参见获取选项)decode页:1. Response.headers.plain()返回信头为普通对象.- 获取选项
follow允许限制要遵循的重定向次数( 默认 :20) (中文(简体) ). - 获取选项
compress允许透明 gzip/deflate/br 内容编码( 默认 ):true) (中文(简体) ). - 获取选项
decode允许透明 gzip/deflate/br 内容解码( 默认 ):true) (中文(简体) ).
注意非标准获取选项已与 节点比对 在适当情况下.
特征
- 支持标准的合理子集 获取规格
- HTTP/1(1)和HTTP/2连接的透明处理
- RFC 7234 (英语) 符合的缓存
- 支助
gzip/deflate/br内容编码 - HTTP/2 请求和响应多功能支持
- HTTP/2 服务器 Push 支持(透明缓存和明确的收听器支持)
- 压倒性用户代理
- 低等HTTP/1.* 代理/连接选项支持(例如:.
keepAlive, (中文(简体) ),rejectUnauthorized(中文(简体) )
安装
说明数字 :
截至v2节点版本需要QQ 12.
$ npm install @adobe/helix-fetch
升级
从旧版本升级 helix-fetch检查以下文件 :
API 密码
除了标准获取 API
fetch()RequestResponseHeadersBody
helix-fetch 曝光以下扩展 :
context()- 创建新定制的 API 上下文reset()- 重置当前 API 上下文,即关闭待决会话/ sockets,清除内部缓存等.onPush()- 注册 HTTP/2 服务器 Push 听器offPush()- 取消先前注册的听众的登记onPush()clearCache()- 清除 HTTP 缓存( 紧急回复)cacheStats()- 返回缓存统计noCache()- 创建适合残疾人缓存的API环境(便利(中文(简体) )h1()- 创建定制的带有HTTP/1.1协议的API上下文(便利(中文(简体) )keepAlive()- 创建一个定制的API上下文,执行HTTP/1.1协议和持续连接(便利(中文(简体) )h1NoCache()- 建立一个定制的API环境,其中包含残疾缓存和执行HTTP/1.1协议(便利(中文(简体) )keepAliveNoCache()- 创建一个定制的API环境,与残疾缓存相接,并强制执行HTTP/1.1协议,与持续连接(便利(中文(简体) )createUrl()- 创建含有查询参数的URL(便利(中文(简体) )timeoutSignal()- 发出超时信号(便利(中文(简体) )
A. 背景情况
API上下文允许自定义执行的某些方面,并按API上下文提供内部结构的隔离(会话缓存,HTTP缓存等).
支持以下选项:
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;
};
常用示例
访问响应信头和其他元数据
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'));
获取 JSON
const { fetch } = require('@adobe/helix-fetch');
const resp = await fetch('https://httpbin.org/json');
const jsonData = await resp.json();
获取文本数据
const { fetch } = require('@adobe/helix-fetch');
const resp = await fetch('https://httpbin.org/');
const textData = await resp.text();
获取二进制数据
const { fetch } = require('@adobe/helix-fetch');
const resp = await fetch('https://httpbin.org//stream-bytes/65535');
const imageData = await resp.buffer();
指定超时 fetch 操作
使用 timeoutSignal(ms) 扩展名 :
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();
}
使用 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);
}
流出图像
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'));
JSON 员额
const { fetch } = require('@adobe/helix-fetch');
const method = 'POST';
const body = { foo: 'bar' };
const resp = await fetch('https://httpbin.org/post', { method, body });
后 JPEG 图像
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 });
表格数据
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 });
获取查询参数对象
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));
或使用 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 });
缓存
答复 GET 财务报告和审定财务报表 HEAD 根据以下规则,请求默认缓存 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);
您可以禁用每个请求的缓存 cache: 'no-store' 选项 :
const { fetch } = require('@adobe/helix-fetch');
const resp = await fetch('https://httbin.org/', { cache: 'no-store' });
assert(resp.ok);
assert(!resp.fromCache);
您可以完全禁用缓存 :
const { fetch } = require('@adobe/helix-fetch').noCache();
高级使用示例
HTTP/2 服务器推
注意被推动的资源将自动透明地添加到缓存中. 不过,您可以添加一个将在每个被驱动(和缓存)的资源上被通知的听众 .
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}`);
强制 HTTP/1(1) 协议
const { fetch } = require('@adobe/helix-fetch').h1();
const resp = await fetch('https://nghttp2.org');
console.log(`Http version: ${resp.httpVersion}`);
HTTP/1.1 保持寿命
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
自签名证书
const { fetch } = require('@adobe/helix-fetch').context({ rejectUnauthorized: false });
const resp = await fetch('https://localhost:8443/'); // a server using a self-signed certificate
设定缓存大小限制
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());
禁用缓存
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);
设置自定义用户代理
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']);
更多实例
可在 测试源文件。 。 。 .
发展
构建
$ npm install
测试
$ npm test
林特
$ npm run lint
解决问题
您可以启用 helix-fetch 设置低级调试控制台输出 DEBUG 环境变量改为 helix-fetch*,例如:
$ DEBUG=helix-fetch* node test.js
这将产生类似于下列控制台外出:
...
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
...
此外,您可以通过设置节点.js低等调试控制台输出 NODE_DEBUG 环境可适当变,例如:.
$ export NODE_DEBUG=http*,stream*
$ export DEBUG=helix-fetch*
$ node test.js
注意:这将用高活字调试输出来淹没控制台.
致谢
感谢 节点比对 财务报告和审定财务报表 gi/牵引 提供坚实的执行参考.