0


实战:Zig 编写高性能 Web 服务(1)

1.1 认识 std.http

std.http 是 Zig 标准库中用于处理 HTTP 相关操作的类库。以我学习新的编程语言的经历来看,编写web程序是最常见的技术场景,所以熟练掌握 HTTP server/client 服务相关的编程知识是比较重要的。

**

  1. std.http

** 主要包含以下API:

  • Client: HTTP client implementation.
  • Server: HTTP server implementation.
  • protocol:headers parse methods.
  • Connection: Connection type (keep_alive, close)
  • ContentEncoding: Content encoding options (compress, deflate, gzip and zstd)
  • Field: Common type for name and value
  • Headers: HTTP headers
  • Method: HTTP methods such as GET and POST
  • Status: HTTP status codes (not_found = 404, teapot = 418, etc.)
  • TransferEncoding: Form of encoding used to transfer the body (chunked)
  • Version: Currently HTTP/1.0 and HTTP/1.1

1.2 编写一个HTTP client程序

先创建一个开工项目:

  1. $ mkdir -p httpz
  2. $ cd httpz
  3. $ zig init
  4. $ ls -ls
  5. total 20
  6. 4 -rw-r--r-- 1 xiaods xiaods 3879 Jun 3 11:53 build.zig
  7. 4 -rw-r--r-- 1 xiaods xiaods 3080 Jun 3 11:50 build.zig.zon
  8. 4 drwxr-xr-x 2 xiaods xiaods 4096 Jun 3 13:33 src
  9. 4 drwxr-xr-x 6 xiaods xiaods 4096 Jun 3 11:51 zig-cache
  10. 4 drwxr-xr-x 4 xiaods xiaods 4096 Jun 3 11:51 zig-out

编辑 src/main.zig,我们将使用 std.heap.GeneralPurposeAllocator,这是一个安全的分配器,可以防止双重释放(double-free)、使用后释放(use-after-free),并且能够检测内存泄漏。

  1. const std = @import("std");
  2. const print = std.debug.print;
  3. const http = std.http;
  4. var gpa = std.heap.GeneralPurposeAllocator(.{}){};
  5. defer _ = gpa.deinit();
  6. const allocator = gpa.allocator();

下一步,为了发送一个请求,我们需要几样东西:

  • client.open 函数
  • 一个从URL解析而来的 std.Uri

下面是我们如何将这些参数组合在一起的方法:

  1. const uri = try std.Uri.parse("http://httpbin.org/headers");
  2. const buf = try allocator.alloc(u8, 1024 * 1024 * 4);
  3. defer allocator.free(buf);
  4. var req = try client.open(.GET, uri, .{
  5. .server_header_buffer = buf,
  6. });
  7. defer req.deinit();

为了真正的发送请求,需要通过send,finish,wait来完成:

  1. try req.send();
  2. try req.finish();
  3. try req.wait();

打印返回的服务器headers 信息:

  1. var iter = req.response.iterateHeaders();
  2. while (iter.next()) |header| {
  3. std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value });
  4. }
  5. try std.testing.expectEqual(req.response.status, .ok);

打印返回的服务端内容:

  1. var rdr = req.reader();
  2. const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
  3. defer allocator.free(body);
  4. print("Body:\n{s}\n", .{body});

把上面的代码所有内容放在一起,并打印出响应内容:

  1. const std = @import("std");
  2. const print = std.debug.print;
  3. const http = std.http;
  4. pub fn main() !void {
  5. var gpa = std.heap.GeneralPurposeAllocator(.{}){};
  6. defer _ = gpa.deinit();
  7. const allocator = gpa.allocator();
  8. var client = http.Client{ .allocator = allocator };
  9. defer client.deinit();
  10. const uri = try std.Uri.parse("http://httpbin.org/headers");
  11. const buf = try allocator.alloc(u8, 1024 * 1024 * 4);
  12. defer allocator.free(buf);
  13. var req = try client.open(.GET, uri, .{
  14. .server_header_buffer = buf,
  15. });
  16. defer req.deinit();
  17. try req.send();
  18. try req.finish();
  19. try req.wait();
  20. var iter = req.response.iterateHeaders();
  21. while (iter.next()) |header| {
  22. std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value });
  23. }
  24. try std.testing.expectEqual(req.response.status, .ok);
  25. var rdr = req.reader();
  26. const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
  27. defer allocator.free(body);
  28. print("Body:\n{s}\n", .{body});
  29. }

跑一下:

  1. $ zig build run
  2. Name:Date, Value:Mon, 03 Jun 2024 08:24:19 GMT
  3. Name:Content-Type, Value:application/json
  4. Name:Content-Length, Value:202
  5. Name:Connection, Value:keep-alive
  6. Name:Server, Value:gunicorn/19.9.0
  7. Name:Access-Control-Allow-Origin, Value:*
  8. Name:Access-Control-Allow-Credentials, Value:true
  9. Body:
  10. {
  11. "headers": {
  12. "Accept-Encoding": "gzip, deflate",
  13. "Host": "httpbin.org",
  14. "User-Agent": "zig/0.12.0 (std.http)",
  15. "X-Amzn-Trace-Id": "Root=1-665d7db3-258c846d0fcca0912fadfa8b"
  16. }
  17. }

成功了!我们成功地向服务器发送了一个GET请求并打印出了响应。

GET请求的例子我们看到了,那么如何发起POST请求呢?让我们继续拿例子说话。

准备好发送内容:

  1. const uri = try std.Uri.parse("http://httpbin.org/anything");
  2. const payload =
  3. \\ {
  4. \\ "name": "zig-learning",
  5. \\ "author": "xiaods"
  6. \\ }
  7. ;

发送POST 请求:

  1. var buf: [1024]u8 = undefined;
  2. var req = try client.open(.POST, uri, .{ .server_header_buffer = &buf });
  3. defer req.deinit();
  4. req.transfer_encoding = .{ .content_length = payload.len };
  5. try req.send();
  6. var wtr = req.writer();
  7. try wtr.writeAll(payload);
  8. try req.finish();
  9. try req.wait();
  10. try std.testing.expectEqual(req.response.status, .ok);

打印返回内容:

  1. var rdr = req.reader();
  2. const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
  3. defer allocator.free(body);
  4. print("Body:\n{s}\n", .{body});

完整的Post代码如下:

  1. const std = @import("std");
  2. const print = std.debug.print;
  3. const http = std.http;
  4. pub fn main() !void {
  5. var gpa = std.heap.GeneralPurposeAllocator(.{}){};
  6. defer _ = gpa.deinit();
  7. const allocator = gpa.allocator();
  8. var client = http.Client{ .allocator = allocator };
  9. defer client.deinit();
  10. const uri = try std.Uri.parse("http://httpbin.org/anything");
  11. const payload =
  12. \\ {
  13. \\ "name": "zig-learning",
  14. \\ "author": "xiaods"
  15. \\ }
  16. ;
  17. var buf: [1024]u8 = undefined;
  18. var req = try client.open(.POST, uri, .{ .server_header_buffer = &buf });
  19. defer req.deinit();
  20. req.transfer_encoding = .{ .content_length = payload.len };
  21. try req.send();
  22. var wtr = req.writer();
  23. try wtr.writeAll(payload);
  24. try req.finish();
  25. try req.wait();
  26. try std.testing.expectEqual(req.response.status, .ok);
  27. var rdr = req.reader();
  28. const body = try rdr.readAllAlloc(allocator, 1024 * 1024 * 4);
  29. defer allocator.free(body);
  30. print("Body:\n{s}\n", .{body});
  31. }

运行结果:

  1. $ zig run src/http-post.zig
  2. Body:
  3. {
  4. "args": {},
  5. "data": " {\n \"name\": \"zig-learning\",\n \"author\": \"xiaods\"\n }",
  6. "files": {},
  7. "form": {},
  8. "headers": {
  9. "Accept-Encoding": "gzip, deflate",
  10. "Content-Length": "52",
  11. "Host": "httpbin.org",
  12. "User-Agent": "zig/0.12.0 (std.http)",
  13. "X-Amzn-Trace-Id": "Root=1-665d8114-01b0167844d8d101012e6d6a"
  14. },
  15. "json": {
  16. "author": "xiaods",
  17. "name": "zig-learning"
  18. },
  19. "method": "POST",
  20. "origin": "219.133.170.77",
  21. "url": "http://httpbin.org/anything"
  22. }

请消化消化以上代码,别着急,我们后面继续前行,编写web server


本文转载自: https://blog.csdn.net/xiaodeshi/article/details/139381098
版权归原作者 xiaodeshi 所有, 如有侵权,请联系我们删除。

“实战:Zig 编写高性能 Web 服务(1)”的评论:

还没有评论