目前 if 和 else 块中的代码有很多的重复:他们都读取文件并将其内容写入流。唯一的区别是状态行和
文件名。为了使代码更为简明,将这些区别分别提取到一行 if 和 else 中,对状态行和文件名变量赋值;
然后在读取文件和写入响应的代码中无条件的使用这些变量。重构后取代了大段 if 和 else 块代码后的
结果如示例 20-9 所示:
文件名: src∕main.rs
use std::fs;
use std::io::prelude:😗;
use std::net::TcpListener;
use std::net::TcpStream;
fn main() {
let listener = TcpListener::bind(“127.0.0.1:7878”).unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
handle_connection(stream);
}
}
// --snip–
fn handle_connection(mut stream: TcpStream) {
// --snip–
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
let get = b"GET / HTTP/1.1\r\n";
let (status_line, filename) = if buffer.starts_with(get) {
(“HTTP/1.1 200 OK”, “hello.html”)
} else {
(“HTTP/1.1 404 NOT FOUND”, “404.html”)
};
534 CHAPTER 20. 最后的项目: 构建多线程 WEB SERVER
let contents = fs::read_to_string(filename).unwrap();
let response = format!(
“{}\r\nContent-Length: {}\r\n\r\n{}”,
status_line,
contents.len(),
contents
);
stream.write(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
示例 20-9: 重构使得 if 和 else 块中只包含两个情况所不同的代码
现在 if 和 else 块所做的唯一的事就是在一个元组中返回合适的状态行和文件名的值;接着使用第十八
章讲到的使用模式的 let 语句通过解构元组的两部分为 filename 和 header 赋值。
之前读取文件和写入响应的冗余代码现在位于 if 和 else 块之外,并会使用变量 status_line 和 filename。
这样更易于观察这两种情况真正有何不同,还意味着如果需要改变如何读取文件或写入响应时只需要更
新一处的代码。示例 20-9 中代码的行为与示例 20-8 完全一样。
好极了!我们有了一个 40 行左右 Rust 代码的小而简单的 server,它对一个请求返回页面内容而对所有
其他请求返回 404 响应。
目前 server 运行于单线程中,它一次只能处理一个请求。让我们模拟一些慢请求来看看这如何会成为一
个问题,并进行修复以便 server 可以一次处理多个请求。