Network - HTTP 客户端
network 命名空间提供了一个完整的 HTTP 客户端,支持常见的 HTTP 方法(GET、POST、PUT、DELETE、HEAD 等),并提供灵活的头部管理和响应处理功能。
版本说明
network 命名空间在 SDK v0.3.2 中引入,取代了旧版的 httpClient 命名空间。旧版 httpClient 仍然可用但建议迁移至 network。
核心接口
HeaderCollection
HTTP 头部集合管理接口:
interface HeaderCollection {
[key: string]: string; // 索引器访问
Set(key: string, value: string): void;
Get(key: string): string;
Contains(key: string): boolean;
Remove(key: string): boolean;
Clear(): void;
GetKeys(): string[];
GetValues(): string[];
}
RequestMessage
HTTP 请求消息结构:
interface RequestMessage {
url: string; // 请求URL
method: string; // HTTP方法
headers: HeaderCollection; // 请求头部
body?: string; // 请求体(可选)
}
ResponseMessage
HTTP 响应消息结构:
interface ResponseMessage {
status: number; // 状态码
headers: HeaderCollection; // 响应头部
body: string; // 响应体
data?: any; // JSON反序列化对象(可选)
}
方法详解
request()
功能描述:发送自定义 HTTP 请求,支持自定义方法、头部和请求体。
语法:
network.request(message: RequestMessage): Promise<ResponseMessage>
参数:
message:完整的请求参数对象url:请求 URLmethod:HTTP 方法headers:请求头集合body:请求体(可选)
使用示例:
const response = await network.request({
url: "https://api.example.com/data",
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer token123"
},
body: JSON.stringify({ status: "active" })
});
logger.info(`状态码: ${response.status}`);
logger.info(`响应: ${response.body}`);
get()
功能描述:发送 GET 请求。
语法:
network.get(url: string): Promise<ResponseMessage>
使用示例:
const response = await network.get("https://api.example.com/users");
if (response.status === 200) {
const users = response.data; // 自动JSON反序列化
logger.info(`获取到 ${users.length} 个用户`);
}
post()
功能描述:发送 POST 请求。
语法:
network.post(url: string, body: any): Promise<ResponseMessage>
使用示例:
const response = await network.post(
"https://api.example.com/users",
JSON.stringify({ name: "张三", email: "zhangsan@example.com" })
);
if (response.status === 201) {
logger.info("用户创建成功");
}
put()
功能描述:发送 PUT 请求。
语法:
network.put(url: string, body: any): Promise<ResponseMessage>
del()
功能描述:发送 DELETE 请求。
语法:
network.del(url: string): Promise<ResponseMessage>
使用示例:
const response = await network.del("https://api.example.com/users/123");
if (response.status === 204) {
logger.info("用户已删除");
}
head()
功能描述:发送 HEAD 请求,仅获取响应头。
语法:
network.head(url: string): Promise<ResponseMessage>
HeaderCollection 方法
索引器访问
直接通过 [] 操作符读写头部:
// 设置
headers["Content-Type"] = "application/json";
// 读取
const contentType = headers["Content-Type"];
Set() / Get()
headers.Set("Authorization", "Bearer token123");
const auth = headers.Get("Authorization");
Contains()
检查是否包含指定头部:
if (headers.Contains("X-Custom-Header")) {
logger.info("包含自定义头部");
}
Remove()
移除指定头部:
headers.Remove("X-Unused-Header");
Clear()
清空所有头部:
headers.Clear();
GetKeys() / GetValues()
遍历所有头部:
const keys = headers.GetKeys();
for (let i = 0; i < keys.length; i++) {
logger.info(`${keys[i]}: ${headers.Get(keys[i])}`);
}
实战示例
调用外部 API
async function fetchWeather(city) {
try {
const response = await network.get(
`https://api.weather.com/v1/current?city=${encodeURIComponent(city)}`
);
if (response.status === 200 && response.data) {
return {
temperature: response.data.current.temp,
condition: response.data.current.condition,
humidity: response.data.current.humidity
};
}
} catch (err) {
logger.error(`天气查询失败: ${err}`);
}
return null;
}
bus.on("group_message_event", async (event) => {
if (event.RawMessage.startsWith("/天气 ")) {
const city = event.RawMessage.substring(4).trim();
const weather = await fetchWeather(city);
if (weather) {
event.Context.Reply(new MessageChain().Text(
`${city}天气:${weather.condition},温度${weather.temperature}°C,湿度${weather.humidity}%`
));
} else {
event.Context.Reply(new MessageChain().Text("天气查询失败"));
}
}
});
带重试的请 求
async function requestWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await network.request({
url: url,
method: options.method || "GET",
headers: options.headers || {},
body: options.body
});
if (response.status >= 200 && response.status < 300) {
return response;
}
logger.warning(`请求失败 (${response.status}),第 ${i + 1} 次重试...`);
} catch (err) {
logger.error(`请求异常: ${err},第 ${i + 1} 次重试...`);
}
// 等待后重试
await new Promise(resolve => threading.setTimeout(resolve, 1000 * (i + 1)));
}
throw new Error(`请求失败,已重试 ${maxRetries} 次`);
}
文件上传 (multipart)
async function uploadFile(filePath, uploadUrl) {
const boundary = "----WebKitFormBoundary" + Math.random().toString(36).substring(2);
const fileBytes = archive.readBytes(filePath);
if (!fileBytes) {
logger.error("文件不存在");
return;
}
// 构造 multipart body
const header = `--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="${filePath}"\r\nContent-Type: application/octet-stream\r\n\r\n`;
const footer = `\r\n--${boundary}--\r\n`;
// 注意:multipart 上传需要使用 request() 方法手动构造
const response = await network.request({
url: uploadUrl,
method: "POST",
headers: {
"Content-Type": `multipart/form-data; boundary=${boundary}`
},
body: header + String.fromCharCode.apply(null, fileBytes) + footer
});
return response;
}
错误处理
async function safeRequest(url) {
try {
const response = await network.get(url);
switch (response.status) {
case 200:
return response.data;
case 401:
logger.error("认证失败,请检查API密钥");
return null;
case 404:
logger.error("请求的资源不存在");
return null;
case 429:
logger.warning("请求过于频繁,请稍后重试");
return null;
case 500:
logger.error("服务器内部错误");
return null;
default:
logger.warning(`未知状态码: ${response.status}`);
return null;
}
} catch (err) {
logger.error(`网络请求异常: ${err}`);
return null;
}
}
与旧版 httpClient 的区别
| 特性 | httpClient (旧) | network (新) |
|---|---|---|
| 命名空间 | httpClient | network |
| 响应数据 | 仅 body | body + data(自动JSON解析) |
| PUT 方法 | 需用 request() | 内置 put() |
| DELETE 方法 | 需 用 request() | 内置 del() |
| HEAD 方法 | 不支持 | 内置 head() |
建议新项目使用
network命名空间,旧版httpClient仍可使用但推荐迁移。
