http.Server - std
自 Zig 0.12.0 起引入了 http.Server 的基本实现。
对于每个连接,我们生成一个新线程来处理它,在 accept 中它将:
- 首先,它使用
defer确保返回时关闭连接。 - 然后初始化 HTTP 服务器以开始解析请求
- 对于每个请求,我们首先检查它是否可以升级到 WebSocket。
- 如果成功,则调用
serveWebSocket,否则调用serverHTTP
- 如果成功,则调用
const std = @import("std");
const log = std.log;
const Request = std.http.Server.Request;
const Connection = std.net.Server.Connection;
const MAX_BUF = 1024;
pub fn main() !void {
const addr = try std.net.Address.parseIp("127.0.0.1", 8080);
var server = try std.net.Address.listen(addr, .{ .reuse_address = true });
defer server.deinit();
log.info("Start HTTP server at {f}", .{addr});
while (true) {
const conn = server.accept() catch |err| {
log.err("failed to accept connection: {s}", .{@errorName(err)});
continue;
};
_ = std.Thread.spawn(.{}, accept, .{conn}) catch |err| {
log.err("unable to spawn connection thread: {s}", .{@errorName(err)});
conn.stream.close();
continue;
};
}
}
fn accept(conn: Connection) !void {
defer conn.stream.close();
log.info("Got new client({f})!", .{conn.address});
var recv_buffer: [1024]u8 = undefined;
var send_buffer: [100]u8 = undefined;
var connection_br = conn.stream.reader(&recv_buffer);
var connection_bw = conn.stream.writer(&send_buffer);
var server = std.http.Server.init(connection_br.interface(), &connection_bw.interface);
while (server.reader.state == .ready) {
var request = server.receiveHead() catch |err| switch (err) {
error.HttpConnectionClosing => return,
else => return err,
};
switch (request.upgradeRequested()) {
.other => |other_protocol| {
log.err("Not supported protocol, {s}", .{other_protocol});
return;
},
.websocket => |key| {
var ws = try request.respondWebSocket(.{ .key = key orelse "" });
try serveWebSocket(&ws);
},
.none => {
try serveHTTP(&request);
},
}
}
}
fn serveHTTP(request: *Request) !void {
try request.respond(
"Hello World from Zig HTTP server",
.{
.extra_headers = &.{
.{ .name = "custom-header", .value = "custom value" },
},
},
);
}
fn serveWebSocket(ws: *std.http.Server.WebSocket) !void {
try ws.writeMessage("Hello from Zig WebSocket server", .text);
while (true) {
const msg = try ws.readSmallMessage();
if (msg.opcode == .connection_close) {
log.info("Client closed the WebSocket", .{});
return;
}
try ws.writeMessage(msg.data, msg.opcode);
}
}
测试
对于 HTTP,我们可以使用 curl:
curl -v localhost:8080
它将输出:
< HTTP/1.1 200 OK
< content-length: 32
< custom header: custom value
<
Hello World from Zig HTTP server
对于 WebSocket,我们可以使用浏览器 开发者工具 中的控制台:
var webSocket = new WebSocket('ws://localhost:8080');
webSocket.onmessage = function(data) { console.log(data); }
然后我们可以像这样发送消息:
webSocket.send('abc')
有关详细信息,请参阅 Writing WebSocket client applications - Web APIs | MDN。
注意
标准库实现的性能极差。如果您计划不仅仅是进行基本的实验,请考虑使用替代库,例如: