Use undici for HTTP requests, fetch, connection pooling, proxies, Mock testing, interceptors, caching.

基于 undici 的高性能 HTTP 客户端,支持请求、代理、Mock 测试和缓存。

已扫描
适合谁
Node.js 开发者、前端/后端测试工程师
不适合谁
无 Node.js 环境的用户、仅需简单 HTTP 调用且不关心性能优化的初学者
国内可用性
需网络配置。可能需要网络配置或第三方服务可访问。
安装难度
新手友好(★☆☆)。基于终端操作、依赖、API Key 和本地环境要求的初步判断。

安装与下载

openclaw skills install @openlark/undici

Skill 说明

命令、参数、文件名以原文为准

undici

Node.js HTTP/1.1 客户端,从零开始编写。作为 Node.js v18+ 内置 fetch() 的底层引擎。当前版本 8.x,支持 ESM/CJS 双模式。

名称含义:意大利语中“十一”的意思 —— 1.1 → 11 → Eleven → Undici(也是《怪奇物语》的彩蛋)

触发场景

当用户需要执行 HTTP 请求、使用 undici、fetch、代理请求或进行 HTTP 模拟测试时使用。

安装

npm i undici

性能优先级

undici.dispatch()  >  undici.request()  >  undici.stream()
>  undici.pipeline()  >  undici.fetch()  >>  node:http

在 50 个 TCP 连接、流水线深度为 10 的情况下,性能约为 axios 的 3-4 倍。

核心用法

request() — 最高层 API,性能最佳

import { request } from 'undici';

const { statusCode, headers, body } = await request('http://localhost:3000/foo');
console.log(statusCode);               // 200
console.log(await body.json());        // 解析 JSON

// body 是一个 Web ReadableStream,也可按块读取:
for await (const chunk of body) {
  console.log('chunk', chunk);
}

// ⚠️ 必须消费响应体!否则会导致连接泄漏
await body.dump(); // 或 .json() / .text() / for await

fetch() — 兼容标准 Web API

import { fetch } from 'undici';

const res = await fetch('https://example.com');
const json = await res.json();

// 使用自定义 Agent
import { Agent } from 'undici';
const res = await fetch('https://example.com', {
  dispatcher: new Agent({ keepAliveTimeout: 10000 })
});

stream() — 流式处理

import { stream } from 'undici';
await stream('http://localhost:3000/foo', { method: 'GET' }, ({ statusCode, headers }) => {
  return new Writable({ write(chunk, _, cb) { console.log(chunk.toString()); cb(); } });
});

pipeline() — 返回 Duplex 流

import { pipeline } from 'undici';
import { Writable, Readable } from 'node:stream';

const duplex = pipeline('http://localhost:3000/foo', { method: 'POST' },
  ({ statusCode, headers }) => new Writable({ /* ... */ })
);
Readable.from(['data']).pipe(duplex);

Agent — 连接池管理

Agent 负责管理多个目标的连接,并自动复用连接:

import { Agent, setGlobalDispatcher, request } from 'undici';

const agent = new Agent({
  connections: 128,         // 每个目标的最大连接数
  pipelining: 10,           // 每个连接的最大流水线深度
  keepAliveTimeout: 4000,   // keep-alive 超时时间(毫秒)
  keepAliveMaxTimeout: 600000,
  bodyTimeout: 300000,
  headersTimeout: 300000,
});

setGlobalDispatcher(agent); // 设置为全局调度器
const data = await request('http://example.com');

内置 fetch 与 undici 模块对比

对比项内置 fetch()(v18+)undici 模块
依赖无依赖需要安装
版本随 Node.js 一起发布可获取最新版本
性能高(存在 Web Streams 开销)request() 性能最优
API仅支持 fetch支持 request/stream/pipeline/dispatch
高级功能✅ 支持 Agent/ProxyAgent/MockAgent/拦截器
错误类型包装为 TypeError提供更明确的错误信息

FormData 一致性

⚠️ fetchFormData 必须来自同一来源:

// ✅ 正确:完全使用 undici
import { fetch, FormData } from 'undici';
const body = new FormData();
body.set('name', 'value');
await fetch(url, { method: 'POST', body });

// ✅ 或调用 install() 替换全局对象
import { install } from 'undici';
install(); // 之后,全局的 fetch/FormData/WebSocket/EventSource 均来自 undici

ProxyAgent — 代理支持

import { ProxyAgent, request, fetch } from 'undici';

const proxyAgent = new ProxyAgent('http://proxy:8080');
// 或带认证:
const proxyAgent = new ProxyAgent({
  uri: 'http://proxy:8080',
  token: `Basic ${Buffer.from('user:pass').toString('base64')}`
});

// 设置为全局
setGlobalDispatcher(proxyAgent);
// 或局部使用
await fetch('http://example.com', { dispatcher: proxyAgent });

MockAgent — 测试模拟

import { MockAgent, setGlobalDispatcher, request } from 'undici';

const mockAgent = new MockAgent();
setGlobalDispatcher(mockAgent);

const mockPool = mockAgent.get('http://localhost:3000');
mockPool.intercept({ path: '/foo', method: 'GET' }).reply(200, { ok: true });

const { body } = await request('http://localhost:3000/foo');
console.log(await body.json()); // { ok: true }

缓存拦截器

import { Agent, interceptors, cacheStores, setGlobalDispatcher } from 'undici';

const client = new Agent().compose(interceptors.cache({
  store: new cacheStores.MemoryCacheStore({
    maxSize: 100 * 1024 * 1024, // 100MB
  }),
  methods: ['GET', 'HEAD']
}));
setGlobalDispatcher(client);

重要注意事项

必须消费响应体

// ✅ 正确做法
const { body } = await request(url);
await body.json(); // 或 .text() / .dump() / for await

// ❌ 错误做法 —— 会导致连接泄漏
const { headers } = await request(url);

// ✅ 如仅需头部信息,建议使用 HEAD 方法
const headers = await fetch(url, { method: 'HEAD' }).then(r => r.headers);

不支持 CORS

undici 不实现浏览器 CORS 机制。在服务器环境中无需预检请求。如需 CORS 保护,需自行实现。

body 混合方法只能调用一次

调用 .text() 后再调用 .json() 会抛出 TypeError: unusable

路径分隔符

始终使用 /。不支持 \ 作为路径分隔符。

参考文档

  • 低层调度器 API(dispatch/handler)→ references/dispatcher.md
  • Agent/Pool/Client 连接管理 → references/connection.md
O
@openlark

已收录 23 个 Skill

相关推荐