当前位置: 首页 > article >正文

Rust配置开发环境+服务器实战

https://www.cnblogs.com/skzxc/p/12129353.html

  1. 默认已经安装好MSVC。

  2. 官网https://www.rust-lang.org/zh-CN/learn/get-started安装Rust安装器,选择winodwsx64版本

  3. 运行安装,将文件夹移动到D盘,安装后,文件夹在C:\Users\xxx下有.cargo.rustup两个文件夹

  4. 新建环境变量

    CARGO_HOME
    D:\Users\xxx\.cargo
    
    RUSTUP_HOME
    D:\Users\xxx\.rustup
    
    path
    %CARGO_HOME%\bin
    
  5. 测试安装成功,输入命令

    cargo --version
    rustup --version
    
  6. 环境变量配置加速安装地址

    RUSTUP_DIST_SERVER
    https://mirrors.tuna.tsinghua.edu.cn/rustup
    RUSTUP_UPDATE_ROOT
    https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup
    
  7. 配置库镜像,在C:\Users\xxx\.cargo下创建config.toml文件,无后缀,复制粘贴

    [source.crates-io]
    registry = "https://github.com/rust-lang/crates.io-index"
    replace-with = "tuna"
    [source.tuna]
    registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
    
  8. 运行安装程序。

  9. 安装VSCode插件

    • Rust Analyzer
    • Even Better TOML
    • CodeLLDB

开发示例

下面包含给出一个Rust服务器的开发示例

给出需求:

  1. 接收两个可选参数:
    1. html_path:默认为index.html,带有路径检查
    2. port:默认为8787
  2. 保存变量html_path,每次浏览器端刷新时,都实时读取html_path返回给服务器渲染。这是为了方便开发和调试。
  3. 开放静态资源给前端。
  4. 允许前端通过/write?filepath=xxx,以及body的数据,写入到服务器端。

开发步骤:

  1. 新建一个项目,命令行输入cargo new myproject

  2. 测试环境配置,编译cargo build

  3. 测试环境配置,运行cargo run

  4. cargo.toml中,复制粘贴

    [package]
    name = "mini_server"
    version = "0.1.0"
    edition = "2024"
    
    [dependencies]
    hyper = { version = "0.14", features = ['full']}
    tokio = { version = "1", features = ["full"] }
    url = '2.3'
    mime_guess = "2.0"
    
  5. src/main.rs中,复制粘贴

    use hyper::service::{make_service_fn, service_fn};
    use hyper::{Body, Method, Request, Response, Server, StatusCode};
    use std::fs;
    use std::net::SocketAddr;
    use std::path::Path;
    use std::sync::Arc;
    use tokio::signal;
    use hyper::body::to_bytes;
    use url::form_urlencoded;
    use mime_guess::from_path;
    
    #[tokio::main]
    async fn main() {
        // 从命令行参数获取HTML文件路径和端口号
        let args: Vec<String> = std::env::args().collect();
        let html_file_path = args.get(1).map(|s| s.as_str()).unwrap_or("index.html");
        let port = args.get(2).and_then(|s| s.parse::<u16>().ok()).unwrap_or(8787);
    
        // 检查文件是否存在
        if !Path::new(html_file_path).exists() {
            eprintln!("File not found: {}", html_file_path);
            return;
        }
    
        // 将HTML文件路径存储在Arc中以便在多个请求之间共享
        let html_file_path = Arc::new(html_file_path.to_string());
    
        // 定义服务处理函数
        let make_svc = make_service_fn(move |_conn| {
            let html_file_path = Arc::clone(&html_file_path);
            async move {
                Ok::<_, hyper::Error>(service_fn(move |req| {
                    let html_file_path = Arc::clone(&html_file_path);
                    async move {
                        handle_request(req, html_file_path).await
                    }
                }))
            }
        });
    
        // 定义服务器地址
        let addr = SocketAddr::from(([127, 0, 0, 1], port));
    
        // 启动服务器
        let server = Server::bind(&addr).serve(make_svc);
    
        // 处理服务器关闭信号
        let graceful = server.with_graceful_shutdown(shutdown_signal());
    
        println!("Server running at http://{}", addr);
    
        // 运行服务器
        if let Err(e) = graceful.await {
            eprintln!("Server error: {}", e);
        }
    }
    
    // 处理HTTP请求
    async fn handle_request(
        req: Request<Body>,
        html_file_path: Arc<String>,
    ) -> Result<Response<Body>, hyper::Error> {
        match (req.method(), req.uri().path()) {
            // 返回HTML内容
            (&Method::GET, "/") => {
                match read_file_to_string(&html_file_path) {
                    Ok(content) => Ok(Response::new(Body::from(content))),
                    Err(e) => {
                        let response = Response::builder()
                            .status(StatusCode::INTERNAL_SERVER_ERROR)
                            .body(Body::from(format!("Failed to read HTML file: {}", e)))
                            .unwrap(); // This unwrap is safe because we know the builder is correctly configured
                        Ok(response)
                    }
                }
            }
    
            // 处理文件写入请求
            (&Method::POST, "/write") => {
                // 解析查询参数
                let query = req.uri().query().unwrap_or_default();
                let params: Vec<(String, String)> = form_urlencoded::parse(query.as_bytes())
                    .into_owned()
                    .collect();
    
                // 获取文件路径参数
                let file_path = params
                    .iter()
                    .find(|(key, _)| key == "filepath")
                    .map(|(_, value)| value.to_string())
                    .unwrap_or_else(|| "example.txt".to_string());
    
                // 读取请求体内容
                let body_bytes = to_bytes(req.into_body()).await?;
                let body_content = String::from_utf8(body_bytes.to_vec()).unwrap_or_default();
    
                // 写入文件
                match write_string_to_file(&file_path, &body_content) {
                    Ok(_) => Ok(Response::new(Body::from("File written successfully"))),
                    Err(e) => {
                        let response = Response::builder()
                            .status(StatusCode::INTERNAL_SERVER_ERROR)
                            .body(Body::from(format!("Failed to write file: {}", e)))
                            .unwrap(); // This unwrap is safe because we know the builder is correctly configured
                        Ok(response)
                    }
                }
            }
    
            (&Method::GET, path) => {
                // 构建文件路径
                let file_path = format!(".{}", path);
                match read_file_to_bytes(&file_path) {
                    Ok(content) => {
                        // 根据文件扩展名猜测MIME类型
                        let mime_type = from_path(&file_path).first_or_octet_stream();
                        let response = Response::builder()
                            .header("Content-Type", mime_type.as_ref())
                            .body(Body::from(content))
                            .unwrap(); // This unwrap is safe because we know the builder is correctly configured
                        Ok(response)
                    }
                    Err(_) => {
                        // 文件不存在,返回404 Not Found
                        let response = Response::builder()
                            .status(StatusCode::NOT_FOUND)
                            .body(Body::from("Not Found"))
                            .unwrap(); // This unwrap is safe because we know the builder is correctly configured
                        Ok(response)
                    }
                }
            }
    
            // 返回404 Not Found
            _ => {
                let response = Response::builder()
                    .status(StatusCode::NOT_FOUND)
                    .body(Body::from("Not Found"))
                    .unwrap(); // This unwrap is safe because we know the builder is correctly configured
                Ok(response)
            }
        }
    }
    
    // 处理服务器关闭信号
    async fn shutdown_signal() {
        // 等待Ctrl+C信号
        signal::ctrl_c()
            .await
            .expect("Failed to install CTRL+C signal handler");
        println!("Shutting down server...");
    }
    
    // 读取文件内容为字符串
    fn read_file_to_string(file_path: &str) -> Result<String, std::io::Error> {
        fs::read_to_string(file_path)
    }
    
    // 将字符串写入文件
    fn write_string_to_file(file_path: &str, content: &str) -> Result<(), std::io::Error> {
        fs::write(file_path, content)
    }
    
    // 读取文件内容为字节数组
    fn read_file_to_bytes(file_path: &str) -> Result<Vec<u8>, std::io::Error> {
        fs::read(file_path)
    }
    
  6. cargo build。让大模型生成一个index.html文件,与生成的exe放进文件夹,点击运行即可。


http://www.kler.cn/a/568789.html

相关文章:

  • DeepSeek 202502 开源周合集
  • Linux系统管理与编程04:基础知识(下)
  • uniapp-原生android插件开发摘要
  • Elasticsearch:使用阿里云 AI 服务进行嵌入和重新排名
  • 算法随笔_62: 买卖股票的最佳时机
  • ViewPager2跟ViewPager的区别
  • 【愚公系列】《鸿蒙原生应用开发从零基础到多实战》006-TypeScript 中的元组
  • 从 Transformer 到 DeepSeek-R1:大型语言模型的变革之路与前沿突破
  • 深入浅出 Go 语言:协程(Goroutine)详解
  • arxiv论文信息爬取与论文pdf下载
  • 游戏引擎学习第128天
  • 【C++经典例题】回文串判断:两种高效解法剖析
  • k8s 中各种发布方式介绍以及对比
  • 本地部署SenseVoice(包括离线设备操作)
  • Java语法基础知识点2
  • 达梦数据库系列之Mysql项目迁移为达梦项目
  • 基于html的俄罗斯方块小游戏(附程序)
  • 技术问题汇总:前端怎么往后端传一个数组?
  • DeepSeek 与大数据治理:AI 赋能数据管理的未来
  • 第十五届蓝桥杯最后一题 拔河问题