https://www.cnblogs.com/skzxc/p/12129353.html
-
默认已经安装好MSVC。
-
官网https://www.rust-lang.org/zh-CN/learn/get-started安装Rust安装器,选择winodws
x64
版本 -
运行安装,将文件夹移动到D盘,安装后,文件夹在
C:\Users\xxx
下有.cargo
和.rustup
两个文件夹 -
新建环境变量
CARGO_HOME D:\Users\xxx\.cargo RUSTUP_HOME D:\Users\xxx\.rustup path %CARGO_HOME%\bin
-
测试安装成功,输入命令
cargo --version rustup --version
-
环境变量配置加速安装地址
RUSTUP_DIST_SERVER https://mirrors.tuna.tsinghua.edu.cn/rustup RUSTUP_UPDATE_ROOT https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup
-
配置库镜像,在
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"
-
运行安装程序。
-
安装VSCode插件
- Rust Analyzer
- Even Better TOML
- CodeLLDB
开发示例
下面包含给出一个Rust服务器的开发示例
给出需求:
- 接收两个可选参数:
html_path
:默认为index.html
,带有路径检查port
:默认为8787
- 保存变量
html_path
,每次浏览器端刷新时,都实时读取html_path
返回给服务器渲染。这是为了方便开发和调试。 - 开放静态资源给前端。
- 允许前端通过
/write?filepath=xxx
,以及body的数据,写入到服务器端。
开发步骤:
-
新建一个项目,命令行输入
cargo new myproject
-
测试环境配置,编译
cargo build
-
测试环境配置,运行
cargo run
-
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"
-
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) }
-
cargo build
。让大模型生成一个index.html
文件,与生成的exe
放进文件夹,点击运行即可。