一个最简单的Http服务(Rust版)

一个最简单的Http服务(Rust版)

1.零依赖版
use std::io::Write;
use std::net::TcpListener;
use std::thread;

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
    println!("Server is running on http://127.0.0.1:8080");
    while let Ok((mut stream, _)) = listener.accept() {
        thread::spawn(move || { // 开启新线程执行请求逻辑
            let contents = "Hello World";
            let size = contents.len();
            let header = format!("HTTP/1.1 200 OK\r\nContent-Length: {size}\r\n\r\n");
            stream.write(header.as_bytes()).unwrap(); // 输出头信息
            stream.write_all(contents.as_bytes()).unwrap(); // 输出 body 内容信息
        });
    }
}
2.使用 异步模块(tokio )版
  • 添加依赖,编辑 Cargo.toml 增加如下内容:
[dependencies]
tokio = { version = "0.3", features = ["full"] }

  • main.rs
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:61383").await.unwrap();
    println!("Server is running on http://127.0.0.1:61383");
    while let Ok((mut stream, _)) = listener.accept().await {
        tokio::spawn(async move {
            let contents = "Hello World";
            let size = contents.len();
            let header = format!("HTTP/1.1 200 OK\r\nContent-Length: {size}\r\n\r\n");
            stream.write(header.as_bytes()).await.unwrap(); // 输出头信息
            stream.write_all(contents.as_bytes()).await.unwrap(); // 输出 body 内容信息
        });
    }
}

3.一撸到底, 下面加上请求头解析,请求体解析
use std::collections::HashMap;
use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader, ReadHalf, split};
use tokio::net::{TcpListener, TcpStream};

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:61383").await.unwrap();
    println!("Server is running on http://127.0.0.1:61383");
    while let Ok((stream, _)) = listener.accept().await {
        tokio::spawn(async move {
            dispatch_request(stream).await
        });
    }
}

async fn dispatch_request(stream: TcpStream) {
    let (mut reader_native, mut writer_native) = split(stream);
    let mut reader = tokio::io::BufReader::new(&mut reader_native);
    let mut writer = tokio::io::BufWriter::new(&mut writer_native);
    let req = parse_request(&mut reader).await;


    // 输出请求头信息
    println!("请求头信息 :");
    for (key, val) in req.headers.iter() {
        println!("{} => {}", key, val);
    }

    println!("请求方式 : {}", req.method);
    println!("请求路由 : {}", req.path);

    let body_len = req.get_content_len();
    println!("请求体大小 : {}", body_len);
    let mut body_buffer = Vec::new();

    while let Ok(code) = reader.read_buf(&mut body_buffer).await {
        if code == 0 {
            break;
        }else if body_buffer.len() >= body_len {
            break;
        }
    }

    println!("请求体: {:?}", String::from_utf8(body_buffer));

    let contents = "Hello World";
    let size = contents.len();
    let header = format!("HTTP/1.1 200 OK\r\nContent-Length: {size}\r\n\r\n");
    writer.write(header.as_bytes()).await.unwrap(); // 输出头信息
    writer.write_all(contents.as_bytes()).await.unwrap(); // 输出 body 内容信息
    writer.flush().await.unwrap();
}


// \r
const _R_: u8 = 13;
// \n
const _N_: u8 = 10;
// :
const _M_: u8 = 58;
// 空格
const _S_: u8 = 32;

struct Req {
    method: String,
    path: String,
    headers: HashMap<String, String>,

}

impl Req {
    fn get_content_len(&self) -> usize {
        let v = self.headers.get("Content-Length");
        return if let Some(c) = v {
            c.parse::<usize>().unwrap_or(0)
        } else if let Some(c) = self.headers.get("content-length") {
            c.parse::<usize>().unwrap_or(0)
        } else {
            0
        };
    }
}

// 请求头解析
async fn parse_request(reader: &mut BufReader<&mut ReadHalf<TcpStream>>) -> Req {
    let mut headers: HashMap<String, String> = HashMap::new();
    let mut req_line = String::new();

    let mut line_count = 0;
    let mut key = String::new();
    let mut val = String::new();
    let mut to_key = true;
    let mut new_line = false;

    while let Ok(code) = reader.read_u8().await {
        if code == 0 {
            break;
        }
        if code == _R_ { // \r\n
            line_count += 1;
            to_key = true;

            if key.len() > 0 { // 上一行的头信息提取
                headers.insert(key.clone().trim().to_string(), val.clone().trim().to_string());
                key.clear();
                val.clear();
            }
            let c2 = reader.read_u8().await.unwrap();
            if c2 != _N_ {
                panic!("http error data");
            }
            if new_line { // 连续换行说明请求头已经结束了
                break;
            }
            new_line = true;
        } else {
            let c = char::from_u32(code as u32).unwrap();
            new_line = false;
            if line_count == 0 {
                req_line.push(c);
            } else {
                if code == _M_ { // 遇到冒号拆分
                    to_key = false;
                    continue;
                }
                if to_key {
                    key.push(c);
                } else {
                    val.push(c);
                }
            }
        }
        // println!("this code: {}, {:?} ", code, char::from_u32(code as u32));
    }
    let mut top = req_line.split(" ");

    return Req {
        method: top.next().unwrap().to_string(),
        path: top.next().unwrap().to_string(),
        headers,
    };
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值