概述
在看书的时候,用到了actix-web这个框架的案例。
书里面的版本是1.0,但是我看官网最新都4.4了。
为了抹平这种信息差,所以我决定把官方提供的示例代码过一遍。
核心代码
Cargo.toml
[package]
name = "hello"
version = "0.1.0"
edition = "2021"[dependencies]
actix-web = "4.4"
env_logger = "0.11"
log = "0.4"
main.rs
rust">use actix_web::{middleware, web, App, HttpRequest, HttpServer};async fn index(req: HttpRequest) -> &'static str {println!("REQ: {req:?}");"Hello world!"
}#[actix_web::main]
async fn main() -> std::io::Result<()> {env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));log::info!("starting HTTP server at http://192.168.77.129:8000");let server = HttpServer::new(|| {App::new().wrap(middleware::Logger::default()).service(web::resource("/index.html").to(|| async {"Hello html!"})).service(web::resource("/").to(index))});server.bind("0.0.0.0:8000")?.run().await
}
运行和访问
http://192.168.77.129:8000/
http://192.168.77.129:8000/index.html
代码解读
引入依赖:
rust">use actix_web::{middleware, web, App, HttpRequest, HttpServer};
首页路由:
- 获取请求信息:
index(req: HttpRequest)
- 返回一个纯文本字符串:
&'static str
rust">async fn index(req: HttpRequest) -> &'static str {println!("REQ: {req:?}");"Hello world!"
}
入口方法:
- 定义入口方法:
#[actix_web::main]
- 声明入口方法:
async fn main() -> std::io::Result<()> {
- 初始化日志:
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
- 记录一个info级别的日志:
log::info!("starting HTTP server at http://192.168.77.129:8000");
- 创建服务对象:
let server = HttpServer::new(|| {
- 使用日志中间件:
.wrap(middleware::Logger::default())
- 挂载路由
/index.html
:.service(web::resource("/index.html").to(|| async {"Hello html!"}))
- 挂载路由
/
:.service(web::resource("/").to(index))
- 启动服务:
server.bind("0.0.0.0:8000")?
rust">#[actix_web::main]
async fn main() -> std::io::Result<()> {env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));log::info!("starting HTTP server at http://192.168.77.129:8000");let server = HttpServer::new(|| {App::new().wrap(middleware::Logger::default()).service(web::resource("/index.html").to(|| async {"Hello html!"})).service(web::resource("/").to(index))});server.bind("0.0.0.0:8000")?.run().await
}
测试代码
actix-web框架还支持对web进行测试。
核心代码如下:
- 创建应用对象:
let app = App::new().route("/", web::get().to(index));
- 设置测试对象:
let app = test::init_service(app).await;
- 构造请求对象:
let req = test::TestRequest::get().uri("/").to_request();
- 发送请求,获取响应:
let resp = app.call(req).await?;
- 断言响应状态码:
assert_eq!(resp.status(), http::StatusCode::OK);
- 获取响应体内容:
let response_body = resp.into_body();
- 断言响应体内容:
assert_eq!(to_bytes(response_body).await?, r##"Hello world!"##);
rust">#[cfg(test)]
mod tests {use actix_web::{body::to_bytes, dev::Service, http, test, Error};use super::*;#[actix_web::test]async fn test_index() -> Result<(), Error> {let app = App::new().route("/", web::get().to(index));let app = test::init_service(app).await;let req = test::TestRequest::get().uri("/").to_request();let resp = app.call(req).await?;assert_eq!(resp.status(), http::StatusCode::OK);let response_body = resp.into_body();assert_eq!(to_bytes(response_body).await?, r##"Hello world!"##);Ok(())}
}
完整代码:
rust">use actix_web::{middleware, web, App, HttpRequest, HttpServer};async fn index(req: HttpRequest) -> &'static str {println!("REQ: {req:?}");"Hello world!"
}#[actix_web::main]
async fn main() -> std::io::Result<()> {env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));log::info!("starting HTTP server at http://192.168.77.129:8000");let server = HttpServer::new(|| {App::new().wrap(middleware::Logger::default()).service(web::resource("/index.html").to(|| async {"Hello html!"})).service(web::resource("/").to(index))});server.bind("0.0.0.0:8000")?.run().await
}#[cfg(test)]
mod tests {use actix_web::{body::to_bytes, dev::Service, http, test, Error};use super::*;#[actix_web::test]async fn test_index() -> Result<(), Error> {let app = App::new().route("/", web::get().to(index));let app = test::init_service(app).await;let req = test::TestRequest::get().uri("/").to_request();let resp = app.call(req).await?;assert_eq!(resp.status(), http::StatusCode::OK);let response_body = resp.into_body();assert_eq!(to_bytes(response_body).await?, r##"Hello world!"##);Ok(())}
}
执行测试:
(base) zhangdapeng@zhangdapeng:~/code/rust/hello$ cargo test
warning: `/home/zhangdapeng/.cargo/config` is deprecated in favor of `config.toml`
note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
warning: `/home/zhangdapeng/.cargo/config` is deprecated in favor of `config.toml`
note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`Finished `test` profile [unoptimized + debuginfo] target(s) in 0.14sRunning unittests src/main.rs (target/debug/deps/hello-4420b7c0e788b52b)running 1 test
test tests::test_index ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s