3
3
4
4
我选择了这个 [ zfz] ( https://github.com/weihanglo/sfz/blob/master/src/main.rs ) 。之所以选择这个项目,是因为它足够小,并且不复杂。用 Rust 实现一些工具的功能,一定能带来很大的收获。我们开始吧!
5
5
6
+ 在了解 sfz 之前,我们应该先了解它的用法。终端输入 ` sfz --help ` 看看都有什么帮助信息。
7
+
8
+ ``` shell
9
+ $ sfz --help
10
+ sfz 0.7.0
11
+ Weihang Lo < me@weihanglo.tw>
12
+
13
+ A simple static file serving command-line tool.
14
+
15
+ USAGE:
16
+ sfz [OPTIONS] [path]
17
+
18
+ ARGS:
19
+ < path> Path to a directory for serving files [default: .]
20
+
21
+ OPTIONS:
22
+ -a, --all Serve hidden and dot (.) files
23
+ -b, --bind < address> Specify bind address [default: 127.0.0.1]
24
+ -c, --cache < seconds> Specify max-age of HTTP caching in seconds [default: 0]
25
+ -C, --cors Enable Cross-Origin Resource Sharing from any origin (* )
26
+ --coi Enable Cross-Origin isolation
27
+ -h, --help Print help information
28
+ -I, --no-ignore Don' t respect gitignore file
29
+ -L, --follow-links Follow symlinks outside current serving base path
30
+ --no-log Don' t log any request/response information.
31
+ -p, --port < port> Specify port to listen on [default: 5000]
32
+ --path-prefix < path> Specify an url path prefix, helpful when running behing a reverse proxy
33
+ -r, --render-index Render existing index.html when requesting a directory.
34
+ -V, --version Print version information
35
+ -Z, --unzipped Disable HTTP compression
36
+
37
+ ```
38
+
39
+ 前面几行主要是应用的名字、版本、作者、描述等信息。我们着重看下 OPTIONS 下对应的参数及其用法。
40
+
41
+ ```
42
+ -a, --all 服务点(`.`)前缀的隐藏文件在内的所有文件。
43
+ -b, --bind <address> 指定 bind 的服务地址 [默认: 127.0.0.1]
44
+ -c, --cache <seconds> 指定 http 缓存的最大秒数,默认 0
45
+ -C, --cors 启用跨域资源访问,任意请求来源
46
+ --coi 启用跨域 isolation
47
+ -h, --help 打印帮助信息
48
+ -I, --no-ignore 忽略 gitignore 文件
49
+ -L, --follow-links 跟随链接符号所指向的路径 Follow symlinks outside current serving base path
50
+ --no-log 不打印请求、响应日志信息
51
+ -p, --port <port> 指定端口号 [默认: 5000]
52
+ --path-prefix <path> 指定一个 url 路径前缀,在反向代理的场景中会很有帮助
53
+ -r, --render-index 请求一个路径时,按照 index.html 文件渲染返回
54
+ -V, --version 打印版本信息
55
+ -Z, --unzipped 禁用 http 压缩
56
+ ```
57
+
58
+ ## 主要思路
59
+ 虽然该工具具备一些“周边”功能,但我们不能脱离主题 —— 围绕实现一个静态资源服务器来分析源代码,因此我们需要有自己的思路,带着自己的想法和问题,去看源代码。下面就是一个参考的思路:
60
+
61
+ * cli 程序的结构
62
+ * 服务器的启动和实现
63
+ * 目录和文件的读取
64
+ * 渲染
65
+ * 响应请求
66
+ * 压缩
67
+
68
+ 所以这篇笔记的思路就按照上方的几个重点来开展。
69
+
70
+ ### cli 程序的结构
71
+ 和很多命令行程序一样,sfz 也是基于 [ clap] ( https://crates.io/crates/clap ) 开发的。作者使用了一种很好的方式,将应用的定义、参数、解析分开在不同的 mod 中,这样看起来不那么零乱了。
72
+
73
+ #### 参数模式
74
+ 首先是 app 的定义,位于 src/cli/app.rs 文件中。由于 app 的生命周期贯穿整个 sfz 的使用,因此有如下定义:
75
+
76
+ ``` rust
77
+ fn app () -> clap :: Command <'static >
78
+ ```
79
+
80
+ 函数体中是一些参数的模式:
81
+
82
+ ```rust
83
+ let arg_port = Arg :: new (" port" )
84
+ . short ('p' )
85
+ . long (" port" )
86
+ . default_value (" 5000" )
87
+ . help (" Specify port to listen on" )
88
+ . value_name (" port" );
89
+ ```
90
+
91
+ 参数的匹配独立到 app 函数中,有利于后期的管理和维护,如果要增加或更新,直接修改 app 函数即可。
92
+
93
+ #### 参数的解析
94
+ 参数解析位于 src/cli/args.rs 文件,命令行参数虽然是看似零乱的标记,但通过匹配拿到后,可以将其放在一个特定的结构中,sfz 就是如此:
95
+
96
+ ``` rust
97
+ #[derive(Debug , Clone , Eq , PartialEq )]
98
+ pub struct Args {
99
+ pub address : String ,
100
+ pub port : u16 ,
101
+ pub cache : u64 ,
102
+ pub cors : bool ,
103
+ pub coi : bool ,
104
+ pub compress : bool ,
105
+ pub path : PathBuf ,
106
+ pub all : bool ,
107
+ pub ignore : bool ,
108
+ pub follow_links : bool ,
109
+ pub render_index : bool ,
110
+ pub log : bool ,
111
+ pub path_prefix : Option <String >,
112
+ }
113
+ ```
114
+
115
+ -- todo
116
+
117
+
118
+ ### 服务器的启动和实现
119
+
120
+
121
+ ### 目录和文件的读取
122
+ ### 渲染
123
+ ### 渲染
124
+ ### 压缩
125
+ ### 响应请求
126
+
6
127
## 错误处理
7
128
由于是一个命令行工具,所以作者对[ 错误处理] ( https://www.cnblogs.com/ishenghuo/p/15864482.html ) 采用了比较直接的方式: ` Box<dyn std::error::Error> ` ,并且,错误的抛出是直接打印然后退出进程:
8
129
@@ -17,4 +138,4 @@ fn handle_err<T>(err: Box<dyn std::error::Error>) -> T {
17
138
18
139
19
140
## 参考
20
- * https://github.com/weihanglo/sfz
141
+ * https://github.com/weihanglo/sfz
0 commit comments