Zig HTTP 网络编程
基于 std.http 的客户端与服务端开发(Zig 0.16.0)。
Capability Boundaries
✅ 强项
- HTTP 客户端请求(GET/POST/PUT/DELETE)
- 自定义请求头、请求体、查询参数
- HTTP 服务端搭建与路由
- WebSocket 客户端与服务端
- TLS/HTTPS 连接
- 连接池管理与压缩
⚠️ 前置要求
- 确认 Zig 版本(
zig version) - 如需 HTTPS 需系统有 CA 证书
❌ 不适用范围
- 非 HTTP 网络编程 → 使用
zig-0.16的 std.net - Zig 语言基础 → 使用
zig-0.16技能
何时使用
- "帮我写一个 HTTP 客户端"
- "如何搭建一个 HTTP 服务器?"
- "用 Zig 调用 REST API"
Data Privacy
本技能不收集、存储或传输任何用户数据。
Workflow
步骤 1. 初始化 Client — std.http.Client{ .allocator = allocator }
步骤 2. 配置请求 — URL、方法、头、请求体
步骤 3. 发送请求 — client.fetch() 或底层 API
步骤 4. 处理响应 — 状态码、响应体
步骤 5. 资源清理 — client.deinit()
HTTP 客户端
快速 GET
var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/data" },
});
std.debug.print("Status: {d}\n", .{@intFromEnum(result.status)});
GET 并读取响应体
var body_buf: [65536]u8 = undefined;
var body_writer: std.Io.Writer = .fixed(&body_buf);
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/data" },
.response_writer = &body_writer,
});
const body = body_writer.buffered();
std.debug.print("Body: {s}\n", .{body});
POST JSON
const payload = "{\"key\": \"value\"}";
var buf: [4096]u8 = undefined;
var body_writer: std.Io.Writer = .fixed(&buf);
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/submit" },
.method = .POST,
.payload = payload,
.response_writer = &body_writer,
.headers = &.{
.{ .name = "Content-Type", .value = "application/json" },
},
});
带查询参数
var uri = std.Uri.parse("https://api.example.com/search")?;
uri.query = "q=zig&limit=10";
const result = try client.fetch(.{ .location = .{ .uri = uri } });
自定义请求头
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/protected" },
.headers = &.{
.{ .name = "Authorization", .value = "Bearer token123" },
.{ .name = "Accept", .value = "application/json" },
},
});
文件上传(multipart)
var form = std.http.Client.Fetch.Form.init(allocator);
defer form.deinit();
try form.field("name", "value");
try form.field("file", file_contents, .{ .filename = "data.txt" });
const result = try client.fetch(.{
.location = .{ .url = "https://api.example.com/upload" },
.method = .POST,
.form = form,
});
底层请求(更细粒度控制)
var req = try client.request(.GET, uri, .{}, .{});
defer req.deinit();
// 发送请求头
try req.send(.{});
// 发送请求体(可选)
try req.writeAll("body data");
// 开始读取响应
try req.finish();
try req.wait();
// 读取响应体
var buf: [4096]u8 = undefined;
var reader_writer: std.Io.Writer = .fixed(&buf);
try req.reader().?.readAllWriter(&reader_writer);
连接池
try client.pool.enable(); // 启用连接池
// 多个请求复用连接
for (urls) |url| {
const result = try client.fetch(.{ .location = .{ .url = url } });
_ = result;
}
HTTP 服务端
基础服务端
pub fn main() !void {
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var server = std.http.Server.init(allocator, .{
.reuse_port = true,
});
defer server.deinit();
const addr = try std.net.Address.parseIp("127.0.0.1", 8080);
try server.listen(addr);
while (true) {
var response_buf: [65536]u8 = undefined;
var req = try server.accept(.{ .response_buffer = &response_buf });
defer req.deinit();
// 响应 Hello World
try req.respond("Hello, World!\n", .{});
}
}
路由分发
while (true) {
var buf: [65536]u8 = undefined;
var req = try server.accept(.{ .response_buffer = &buf });
defer req.deinit();
const url = req.request.target;
if (std.mem.eql(u8, url, "/api/hello")) {
try req.respond("{\"msg\": \"hello\"}", .{ .content_type = .json });
} else if (std.mem.eql(u8, url, "/api/status")) {
try req.respond("{\"status\": \"ok\"}", .{ .content_type = .json });
} else {
try req.respond("Not Found", .{ .status = .not_found });
}
}
JSON 响应
const body = "{\"name\": \"server\", \"version\": \"1.0\"}";
try req.respond(body, .{ .content_type = .json });
读取请求体
var req_body: [4096]u8 = undefined;
const body_len = try req.readAll(&req_body);
const body = req_body[0..body_len];
// 处理 body...
try req.respond("OK", .{});
WebSocket
// 服务端升级到 WebSocket
var ws = try req.upgradeToWebSocket(.{});
defer ws.deinit();
while (true) {
const frame = try ws.readFrame() orelse break;
std.debug.print("Received: {s}\n", .{frame.payload});
try ws.writeFrame("echo: " ++ frame.payload);
}
Gotchas
- std.http 在 0.16 中是实验性的 — API 可能在未来版本变化
- Client 必须 deinit —
client.deinit()释放连接池和资源 - 响应体大小限制 —
fetch()默认不限制大小,但自行提供固定 buffer 时注意溢出 - HTTPS 需要系统 CA — 在容器或无 CA 的环境中可能需要配置
server.ca_bundle - Server.listen 的 addr — IPv4 用
127.0.0.1,IPv6 用[::1]
FAQ
Q:如何设置超时?
A:使用底层 API(client.request + req.wait())可以控制超时。fetch() 高层 API 暂不支持超时。
Q:最大并发连接数? A:默认 128。启用连接池后自动管理复用,不显式限制。
Q:支持 HTTP/2 吗? A:std.http 目前仅支持 HTTP/1.1。HTTP/2 支持计划中。