Contents

Rust实现Http Web Server

用Rust实现WebSerer的第一篇

最近业余时间一直在学习Rust,也在尝试用Rust去造轮子。第一个轮子就是用Rust去实现Web服务器。Web服务器的核心流程就是RequestResponse。 简单的总结就是解析请求,然后匹配到Server初始化的路由处理器,然后路由处理器处理完返回

同步版本的程序

  • 启动TCP服务
  • 解析处理请求
  • 匹配路由
  • 返回响应

示范代码如下


use sync_core::server::Server;
use sync_core::service::Service;

fn main() {
    //trace log
    tracing_subscriber::fmt::init();
    let mut server = Server::new(Service::new());

    let route = sync_core::route::Route::new("GET".to_string(), "/hello".to_string(), || {
        "Hello World".to_string()
    });

    // hello world 2 return int value
    let route2 = sync_core::route::Route::new("GET".to_string(), "/hello2".to_string(), || {
        //i32 value return
        42.to_string()
    });

    // push route to server
    server.service.routes.push(route);
    server.service.routes.push(route2);

    server.start();
}


use crate::service::Service;
use log::info;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};

pub struct Server {
    pub service: Service,
}

impl Server {
    pub fn new(service: Service) -> Self {
        Self { service }
    }

    pub fn start(&self) {
        let addr = "127.0.0.1:8080";
        let listener = TcpListener::bind(addr).unwrap();
        info!("Listening on http://{}", addr);
        for stream in listener.incoming() {
            match stream {
                Ok(stream) => {
                    self.handle_connection(stream);
                }
                Err(e) => {
                    eprintln!("failed: {}", e);
                }
            }
        }
    }

    fn handle_connection(&self, mut tcp_stream: TcpStream) {
        let mut buffer = [0; 1024];
        tcp_stream.read(&mut buffer).unwrap();
        info!("Request: {}", String::from_utf8_lossy(&buffer));
        // parse request
        let request = String::from_utf8_lossy(&buffer);
        let request = request.split_whitespace().collect::<Vec<&str>>();
        let method = request[0];
        let path = request[1];
        let _version = request[2];
        info!("Method: {}", method);
        info!("Path: {}", path);
        info!("Version: {}", _version);
        // find route
        let route = self
            .service
            .routes
            .iter()
            .find(|r| r.method == method && r.path == path);
        match route {
            Some(route) => {
                let response_body = (route.handler)();
                let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", response_body);
                tcp_stream.write(response.as_bytes()).unwrap();
            }
            None => {
                let response_body = "Not Found Route";
                let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", response_body);
                tcp_stream.write(response.as_bytes()).unwrap();
            }
        }
    }
}

use crate::route::Route;

pub struct Service {
    pub routes: Vec<Route>,
}

impl Service {
    pub fn new() -> Self {
        Self { routes: Vec::new() }
    }
}


pub struct Route {
    pub method: String,
    pub path: String,
    pub handler: fn() -> String,
}

impl Route {
    pub fn new(method: String, path: String, handler: fn() -> String) -> Self {
        Self {
            method,
            path,
            handler,
        }
    }
}