
✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:Rust语言通关之路
景天的主页:景天科技苑

文章目录
- Rust http编程
- 1. HTTP基础与Rust生态系统
- 1.1 HTTP协议回顾
- 1.2 Rust HTTP生态系统概览
- 2. 使用标准库进行HTTP编程
- 2.1 基本HTTP服务端
- 2.2 简单HTTP客户端
- 2.3 服务端响应网页
- 2.4 有条件地响应网页
- 2.5 多线程的http服务器
- 2.6 线程池webserver
- 2.7 实现线程池清除的webserver
Rust http编程
Rust作为一门系统级编程语言,凭借其出色的性能、内存安全性和并发特性,在网络编程领域展现出强大的潜力。
本文将详细介绍如何使用Rust进行HTTP编程,涵盖从基础概念到实际应用的各个方面。
1. HTTP基础与Rust生态系统
1.1 HTTP协议回顾
HTTP(HyperText Transfer Protocol)是应用层协议,基于请求-响应模型工作。Rust提供了多种处理HTTP协议的方式:
标准库:基础但功能有限
第三方库:功能丰富,如reqwest、hyper等
Web框架:如actix-web、rocket等
1.2 Rust HTTP生态系统概览
Rust的HTTP生态系统包含多个层次的组件:
底层库:hyper、h2、http等
客户端库:reqwest、ureq等
服务器框架:actix-web、rocket、warp等
工具库:serde(序列化)、tokio(异步运行时)等
2. 使用标准库进行HTTP编程
虽然不推荐在生产环境中使用标准库进行HTTP编程,但了解其基本用法有助于理解底层原理。
可以参考官方标准库net库 https://doc.rust-lang.org/stable/std/net/index.html
TcpListener可以创建http客户端和服务端

HTTP简单介绍
(1)http请求报文包含三个部分内容 :请求行、请求头 、请求体
Method Request-URI HTTP-Version CRLF //请求行:请求方式、协议版本等
headers CRLF //请求头:包含若干个属性,格式为“属性名:属性值”,格式为"属性名:属性值",服务端据此获取客户端的信息
message-body //请求体 :客户端真正要传送给服务端的内容
(2)http响应报文也有三部分内容:响应行、响应头、响应体
HTTP-Version status-Code Reason-Phrase CRLF //响应行:报文协议及版本,状态码及状态描述
headers CRLF //响应头:由多个属性组成
message-body //响应体:真正响应的内容
2.1 基本HTTP服务端
主要使用标准库中的net库和io库
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Writefn handle_client(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//构建http响应,向客户端打招呼//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//将响应写入到客户端stream.write_all(response.as_bytes()).unwrap();//刷新缓冲区stream.flush().unwrap();
}fn main() -> std::io::Result<()> {//创建监听器let listener = TcpListener::bind("127.0.0.1:8080")?;//处理客户端请求//listener.incoming()返回一个迭代器,用于接收客户端的连接请求for stream in listener.incoming() {//处理客户端请求的逻辑//listener.incoming()返回的迭代器包含错误,需要使用?来处理handle_client(stream?);}Ok(())
}
2.2 简单HTTP客户端
use std::io::{ Read, Write };
use std::net::TcpStream;fn main() -> std::io::Result<()> {//创建TCP连接let mut stream = TcpStream::connect("localhost:8080")?;//构建HTTP请求let request ="GET / HTTP/1.1\r\n\Host: localhost:8080\r\n\Connection: close\r\n\\r\n";stream.write_all(request.as_bytes())?;//创建个缓冲区,用于读取服务器的响应let mut buffer = Vec::new();//读取服务器的响应stream.read_to_end(&mut buffer)?;//打印服务器的响应println!("{}", String::from_utf8_lossy(&buffer));Ok(())
}
服务端收到客户端请求

客户端收到服务端响应

2.3 服务端响应网页
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Writefn handle_client(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//构建http响应,向客户端打招呼//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//从文件读取内容响应给客户端let content = std::fs::read_to_string("index.html").unwrap();let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);//将响应写入到客户端stream.write_all(response.as_bytes()).unwrap();//刷新缓冲区stream.flush().unwrap();
}fn main() -> std::io::Result<()> {//创建监听器let listener = TcpListener::bind("127.0.0.1:8080")?;//处理客户端请求//listener.incoming()返回一个迭代器,用于接收客户端的连接请求for stream in listener.incoming() {//处理客户端请求的逻辑//listener.incoming()返回的迭代器包含错误,需要使用?来处理handle_client(stream?);}Ok(())
}
直接浏览器访问查看

2.4 有条件地响应网页
有条件地响应网页,主要是对客户端的请求进行判断,不同的请求路径、请求方法等响应不同内容
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Writefn handle_client(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//构建http响应,向客户端打招呼//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//获取客户端的请求方法let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_method = request_method.split(" ").nth(0).unwrap();println!("Request method: {}", request_method);//判断请求方法是否为GETif request_method != "GET" {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();return;} else {//获取客户端的请求路径let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_path = request_path.split(" ").nth(1).unwrap();println!("Request path: {}", request_path);//判断请求路径是否为/if request_path == "/" {let content = std::fs::read_to_string("index.html").unwrap();let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();return;} else {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();return;}}
}fn main() -> std::io::Result<()> {//创建监听器let listener = TcpListener::bind("127.0.0.1:8080")?;//处理客户端请求//listener.incoming()返回一个迭代器,用于接收客户端的连接请求for stream in listener.incoming() {//处理客户端请求的逻辑//listener.incoming()返回的迭代器包含错误,需要使用?来处理handle_client(stream?);}Ok(())
}
get方法 /路径

get方法其他路径

代码优化,将一些重复的代码封装
use std::net::{ TcpListener, TcpStream }; //导入TcpListener和TcpStream
use std::io::{ Read, Write }; //导入Read和Writefn handle_client(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//获取客户端的请求方法let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_method = request_method.split(" ").nth(0).unwrap();println!("Request method: {}", request_method);//封装一个函数,响应客户端fn response_client(mut stream: TcpStream, response: String) {stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();}//判断请求方法是否为GETif request_method != "GET" {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {//获取客户端的请求路径let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_path = request_path.split(" ").nth(1).unwrap();println!("Request path: {}", request_path);//判断请求路径是否为/if request_path == "/" {let content = std::fs::read_to_string("index.html").unwrap();let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);}}
}fn main() -> std::io::Result<()> {//创建监听器let listener = TcpListener::bind("127.0.0.1:8080")?;//处理客户端请求//listener.incoming()返回一个迭代器,用于接收客户端的连接请求for stream in listener.incoming() {//处理客户端请求的逻辑//listener.incoming()返回的迭代器包含错误,需要使用?来处理handle_client(stream?);}Ok(())
}
2.5 多线程的http服务器
单线程的的webserver存在的问题:
请求只能串行处理,也就是说当第一个连接处理完之前不会处理第二个连接。
这样,当有海量请求的时候,就会出问题
我们采用多线程
//多线程的http服务器
use std::thread;
use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };fn handle_client(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//获取客户端的请求方法let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_method = request_method.split(" ").nth(0).unwrap();println!("Request method: {}", request_method);//封装一个函数,响应客户端fn response_client(mut stream: TcpStream, response: String) {stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();}//判断请求方法是否为GETif request_method != "GET" {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {//获取客户端的请求路径let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_path = request_path.split(" ").nth(1).unwrap();println!("Request path: {}", request_path);//判断请求路径是否为/if request_path == "/" {let content = std::fs::read_to_string("index.html").unwrap();let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);}}
}fn main() -> std::io::Result<()> {//创建监听器let listener = TcpListener::bind("127.0.0.1:8080")?;//创建线程句柄let mut handles = Vec::new();//处理客户端请求//listener.incoming()返回一个迭代器,用于接收客户端的连接请求for stream in listener.incoming() {//处理客户端请求的逻辑//使用多线程let handle = thread::spawn(move || {handle_client(stream.unwrap());});handles.push(handle);}//等待所有线程结束for handle in handles {handle.join().unwrap();}Ok(())
}
2.6 线程池webserver
上面通过多线程创建的webserver,当请求不断太多时,还是可以用一用。
但是当请求比较海量时,系统也会跟着创建海量的线程,最终造成系统资源耗尽而崩溃
此时,我们采用线程池来处理

多线程,管道
从主线程将任务发送到管道,工作线程等待在管道的接收端,当收到任务时,进行处理。
✅ 创建文件结构:
.
├── main.rs
├── lib.rs // 线程池模块
🔧 Cargo.toml(依赖可以不用加,使用标准库)
[package]
name = "myhttpserver3"
version = "0.1.0"
edition = "2024"[dependencies]
📄 src/main.rs
use std::net::TcpListener;
use std::io::prelude::*;
use std::net::TcpStream;
use myhttpserver3::ThreadPool; //这里myhttpserver3是Cargo.toml中定义的依赖库名称,就是项目的名称fn main() {//创建监听器,监听7878端口let listener = TcpListener::bind("127.0.0.1:7878").unwrap();//创建线程池,线程池大小为4let pool = ThreadPool::new(4);println!("Server running on 127.0.0.1:7878");//使用线程池处理请求for stream in listener.incoming().take(10) {let stream = stream.unwrap();pool.execute(|| {handle_connection(stream);});}println!("Shutting down.");
}fn handle_connection(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//获取客户端的请求方法let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_method = request_method.split(" ").nth(0).unwrap();println!("Request method: {}", request_method);//封装一个函数,响应客户端fn response_client(mut stream: TcpStream, response: String) {stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();}//判断请求方法是否为GETif request_method != "GET" {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {//获取客户端的请求路径let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_path = request_path.split(" ").nth(1).unwrap();println!("Request path: {}", request_path);//判断请求路径是否为/if request_path == "/" {let content = std::fs::read_to_string("index.html").unwrap();let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);}}
}
📄 src/lib.rs
//线程池
use std::sync::{ Arc, Mutex };
use std::sync::mpsc;
use std::thread;//定义一个结构体,表示线程池
#[allow(dead_code)]
pub struct ThreadPool {workers: Vec<Worker>,sender: mpsc::Sender<Job>,
}//使用type关键字定义一个类型别名,表示任务。使用type起类型别名,用于简化代码
//这个类型是依照ThreadPool的excute()方法的参数类型来的
type Job = Box<dyn FnOnce() + Send + 'static>;//为ThreadPool实现方法
impl ThreadPool {// 创建新线程池pub fn new(size: usize) -> ThreadPool {//线程池的大小必须大于0assert!(size > 0);println!("Creating a thread pool of size {}", size);//创建通道let (sender, receiver) = mpsc::channel();//将接收端放入互斥锁中,再放入Arc中,实现共享let receiver = Arc::new(Mutex::new(receiver));//创建线程池let mut workers = Vec::with_capacity(size);//创建工作线程for id in 0..size {workers.push(Worker::new(id, Arc::clone(&receiver)));}//返回线程池ThreadPool { workers, sender }}// 执行任务。这里是参照标准库 thread::spawn()的实现的//对F有约束pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {//将任务包装成Boxlet job = Box::new(f);self.sender.send(job).unwrap();}
}//定义一个结构体,表示工作线程
#[allow(dead_code)]
struct Worker {id: usize, //工作线程的idthread: thread::JoinHandle<()>, //线程句柄
}//为Worker实现方法
impl Worker {//接收端需要线程安全,所以需要Arc<Mutex<T>>fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {//创建工作线程let thread = thread::spawn(move || {//循环从通道中接收任务,并执行loop {//recv会阻塞线程,直到有数据可读let job = receiver.lock().unwrap().recv().unwrap();println!("Worker {} got a job; executing.", id);//执行任务job();}});//返回工作线程Worker { id, thread }}
}
📄 index.html(放在项目根目录)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><h1>Hello, Jingtian!</h1></body>
</html>
📄 404.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><h1>Oops!</h1><p>The page you are looking for does not exist.</p></body>
</html>
运行服务器
cargo run
然后在浏览器打开 http://127.0.0.1:7878/

如果是其他路径

2.7 实现线程池清除的webserver
在之前的用线程池实现的webserver中,每个工作线程中通过loop进行循环,从channel的接收端等待任务,然后执行。
但是在代码中,work采用的是loop循环,没有跳出循环的条件,没有提供一种机制,来通知工作线程结束。
现在我们就来实现线程池对象的正确清除。
通过为ThreadPool实现Drop trait来实现线程池对象清除
修改Worker如下:
struct Worker {id: usize, //工作线程的id//线程句柄,将thread::JoinHandle<()>包装成Option,用于在drop()方法中调用take()方法//Option中有take()方法,可以将Some中的值取出来,同时将Some置为Nonethread: Option<thread::JoinHandle<()>>,
}
Option中有take方法

完成的代码:
src/lib.rs
//线程池
use std::sync::{ Arc, Mutex };
use std::sync::mpsc;
use std::thread;//定义一个结构体,表示线程池
#[allow(dead_code)]
pub struct ThreadPool {workers: Vec<Worker>,// sender: mpsc::Sender<Job>,sender: mpsc::Sender<Message>,
}//使用type关键字定义一个类型别名,表示任务。使用type起类型别名,用于简化代码
//这个类型是依照ThreadPool的excute()方法的参数类型来的
type Job = Box<dyn FnOnce() + Send + 'static>;//发送结束消息给worker,所有发送job的地方都要修改
enum Message {//两种情况NewJob(Job),Terminate,
}//为ThreadPool实现方法
impl ThreadPool {// 创建新线程池pub fn new(size: usize) -> ThreadPool {//线程池的大小必须大于0assert!(size > 0);println!("Creating a thread pool of size {}", size);//创建通道let (sender, receiver) = mpsc::channel();//将接收端放入互斥锁中,再放入Arc中,实现共享let receiver = Arc::new(Mutex::new(receiver));//创建线程池let mut workers = Vec::with_capacity(size);//创建工作线程for id in 0..size {workers.push(Worker::new(id, Arc::clone(&receiver)));}//返回线程池ThreadPool { workers, sender }}// 执行任务。这里是参照标准库 thread::spawn()的实现的//对F有约束pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {//将任务包装成Boxlet job = Box::new(f);// self.sender.send(job).unwrap();self.sender.send(Message::NewJob(job)).unwrap();}
}//为ThreadPool实现Drop trait
impl Drop for ThreadPool {//当线程池被销毁时,关闭所有工作线程//实现Drop trait,只需要实现drop()方法即可fn drop(&mut self) {//发送结束消息给workerfor _ in &self.workers {self.sender.send(Message::Terminate).unwrap();}//等待所有工作线程结束for worker in &mut self.workers {println!("Shutting down worker {}", worker.id);//等待工作线程结束if let Some(thread) = worker.thread.take() {thread.join().unwrap();}}}
}//定义一个结构体,表示工作线程
#[allow(dead_code)]
struct Worker {id: usize, //工作线程的id//线程句柄,将thread::JoinHandle<()>包装成Option,用于在drop()方法中调用take()方法//Option中有take()方法,可以将Some中的值取出来,同时将Some置为Nonethread: Option<thread::JoinHandle<()>>,
}//为Worker实现方法
impl Worker {//接收端需要线程安全,所以需要Arc<Mutex<T>>fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {//创建工作线程let thread = thread::spawn(move || {//循环从通道中接收任务,并执行loop {//recv会阻塞线程,直到有数据可读// let job = receiver.lock().unwrap().recv().unwrap();let message = receiver.lock().unwrap().recv().unwrap();// println!("Worker {} got a job; executing.", id);//判断消息类型match message {Message::NewJob(job) => {println!("Worker {} got a job; executing.", id);job();}Message::Terminate => {println!("Worker {} was told to terminate.", id);//收到结束消息,退出循环break;}}}});//返回工作线程Worker { id, thread: Some(thread) }}
}
src/main.rs
use std::net::TcpListener;
use std::io::prelude::*;
use std::net::TcpStream;
use myhttpserver4::ThreadPool; //这里myhttpserver3是Cargo.toml中定义的依赖库名称,就是项目的名称fn main() {//创建监听器,监听7878端口let listener = TcpListener::bind("127.0.0.1:7878").unwrap();//创建线程池,线程池大小为4let pool = ThreadPool::new(4);println!("Server running on 127.0.0.1:7878");//使用线程池处理请求//listener.incoming()返回一个迭代器,用于接收客户端的连接请求//take(4)表示只接收4个连接请求,可以根据实际情况调整for stream in listener.incoming().take(4) {let stream = stream.unwrap();pool.execute(|| {handle_connection(stream);});}println!("Shutting down.");
}fn handle_connection(mut stream: TcpStream) {//读取客户端请求,每次读取1024个字节let mut buffer = [0; 1024];stream.read(&mut buffer).unwrap();//打印客户端请求println!("Request: {}", String::from_utf8_lossy(&buffer[..]));//获取客户端地址let client_addr = stream.peer_addr().unwrap();println!("New connection: {}", client_addr);// let response = format!("HTTP/1.1 200 OK\r\n\r\nhello {client_addr}!");//获取客户端的请求方法let request_method = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_method = request_method.split(" ").nth(0).unwrap();println!("Request method: {}", request_method);//封装一个函数,响应客户端fn response_client(mut stream: TcpStream, response: String) {stream.write_all(response.as_bytes()).unwrap();stream.flush().unwrap();}//判断请求方法是否为GETif request_method != "GET" {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {//获取客户端的请求路径let request_path = std::str::from_utf8(&buffer).unwrap().lines().next().unwrap();let request_path = request_path.split(" ").nth(1).unwrap();println!("Request path: {}", request_path);//判断请求路径是否为/if request_path == "/" {let content = std::fs::read_to_string("index.html").unwrap();let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);} else {let content = std::fs::read_to_string("404.html").unwrap();let response = format!("HTTP/1.1 404 Not Found\r\n\r\n{}", content);// stream.write_all(response.as_bytes()).unwrap();// stream.flush().unwrap();response_client(stream, response);}}
}
接收4个请求后,服务器就关闭