【Rust Crate之Actix Web(一)】

news/2024/11/13 7:04:29/

Rust Crate之Actix Web

  • 什么是Actix Web?
  • Actix Web 入门
    • 代码宏展开,看看` #[get("/")] ` 做了什么
    • Actix Web中的State
    • Actix Web中的scope
    • Actix Web中的extractors
      • Path
      • Query
      • JSON
      • URL-encoded form
  • 总结


什么是Actix Web?

Actix Web is a poweful ,pragmatic,and extremely fast web framework for Rust

Actix Web 作为一个服务器框架,非常适合于搭建小型http服务器,方便快捷,它支持Http/1,Http2,TLS,尽管他也支持了Websocket,但在此不予讨论。

Actix Web 入门

代码示例:

rust">use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};#[get("/")]           //使用ACtix定义的宏,可以直接将响应函数定义具体路由地址(url),并确定以什么方式访问(如这里的根,Get方式),
async fn hello() -> impl Responder {HttpResponse::Ok().body("Hello world!")
}#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {HttpResponse::Ok().body(req_body)
}async fn manual_hello() -> impl Responder {HttpResponse::Ok().body("Hey there!")
}#[actix_web::main]  //标明Actix web程序入口,默认支持异步编程
async fn main() -> std::io::Result<()> {HttpServer::new(|| { //创建HttpServerApp::new()       //使用App 实例注册request处理程序..service(hello) //使用宏路由的,用sercvice注册.service(echo)  .route("/hey", web::get().to(manual_hello)) //也可以手动,更清晰的注册路由}).bind(("127.0.0.1", 8080))?//绑定具体的Ip & Port.run()            //run起来您的程序.await
}
//ps:以上代码为官方示例

代码宏展开,看看#[get("/")] 做了什么

rust">#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
#[allow(non_camel_case_types, missing_docs)]
pub struct hello;
// 正如官文中描述的那样:Finally, the app is started inside an HttpServer which will serve incoming 
// requests using your App as an "application factory". 每一个request处理程序都实现了HttpServiceFactory
impl ::actix_web::dev::HttpServiceFactory for hello {fn register(self, __config: &mut actix_web::dev::AppService) {//register将会在Service做为参数传入时,最终调用HttpServiceFactory::register将resource注册async fn hello() -> impl Responder {HttpResponse::Ok().body("Hello world!")}let __resource = ::actix_web::Resource::new("/").name("hello").guard(::actix_web::guard::Get()).to(hello);::actix_web::dev::HttpServiceFactory::register(__resource, __config);}
}
#[allow(non_camel_case_types, missing_docs)]
pub struct echo;
impl ::actix_web::dev::HttpServiceFactory for echo {fn register(self, __config: &mut actix_web::dev::AppService) {async fn echo(req_body: String) -> impl Responder {HttpResponse::Ok().body(req_body)}let __resource = ::actix_web::Resource::new("/echo").name("echo").guard(::actix_web::guard::Post()).to(echo);::actix_web::dev::HttpServiceFactory::register(__resource, __config);}
}
async fn manual_hello() -> impl Responder {HttpResponse::Ok().body("Hey there!")
}
fn main() -> std::io::Result<()> {<::actix_web::rt::System>::new().block_on(async move {{HttpServer::new(|| {App::new().service(hello).service(echo).route("/hey", web::get().to(manual_hello))}).bind(("127.0.0.1", 8080))?.run().await}})
}

Actix Web中的State

Actix web 框架下的State,即承载Server内部非请求数据的数据载体,不要被名称迷惑,它可以通过自定义数据来表示Server的状态,而更多的是用以共享全局性质的变量,通常来讲,如在开发时对数据库链接管理的数据库连接池,也可以是只读的base_url,在共享此类变量时需要注意,Actix Web Server针对每一条数据请求都是会独立出一条thread,所以共享时的同步尤为重要,所以在实现自定义的数据时,请注意使用同步原语。
代码示例:

rust">...
let db_pool = Data::new(db_pool);
....app_data(db_pool.clone())...

State在闭包直接初始化时是无法做同步的,当开发者需要同步机制,则需要如上述代码一般,先在外部声明,再clone传入。

Actix Web中的scope

Scope表示范围,在服务中即表示统一前缀,举个例子:/user/login /user/info中的/user便是前缀,这方便开发者将api以restful形式拆分,更好的做分类,进一步的,开发者可以通过ServiceConfig 将具体的请求处理程序分配到不同的module中,使得整个程序代码更加的结构化。

rust">use actix_web::{web, App, HttpResponse, HttpServer};// this function could be located in a different module
fn scoped_config(cfg: &mut web::ServiceConfig) {cfg.service(web::resource("/test").route(web::get().to(|| async { HttpResponse::Ok().body("test") })).route(web::head().to(HttpResponse::MethodNotAllowed)),);
}// this function could be located in a different module
fn config(cfg: &mut web::ServiceConfig) {cfg.service(web::resource("/app").route(web::get().to(|| async { HttpResponse::Ok().body("app") })).route(web::head().to(HttpResponse::MethodNotAllowed)),);
}#[actix_web::main]
async fn main() -> std::io::Result<()> {HttpServer::new(|| {App::new().configure(config).service(web::scope("/api").configure(scoped_config)).route("/",web::get().to(|| async { HttpResponse::Ok().body("/") }),)}).bind(("127.0.0.1", 8080))?.run().await
}
//ps: 例子来源于官文

Actix Web中的extractors

extractors在Acitx Web中是类型安全的,extractors提供了提取请求数据中为特定类型的不同方法,使得代码更加清晰安全.

Path

Path用于将请求路径上的信息转为自定义类型。

rust">//具体的
#[derive(Deserialize)] //自定义类型一定需要实现反序列化
struct Info {user_id: u32,friend: String,
}
/// extract path info using serde
#[get("/users/{user_id}/{friend}")] //宏中名称要和自定义类型中的名称对齐.
async fn index(info: web::Path<Info>) -> Result<String> {Ok(format!("Welcome {}, user_id {}!",info.friend, info.user_id))
}

Query

Query用于请求参数的提取,将其转换成具体的类型。

rust">#[derive(Deserialize)]
struct Info {username: String,
}//如果请求参数中并不包含需要提取的字段数据,则server将会返回404
#[get("/")]
async fn index(info: web::Query<Info>) -> String {format!("Welcome {}!", info.username)
}

JSON

JSON 用于将请求中的json格式请求体转为具体的类型。

rust">use actix_web::{post, web, App, HttpServer, Result};
use serde::Deserialize;#[derive(Deserialize)]
struct Info {username: String,
}/// deserialize `Info` from request's body
#[post("/submit")]
async fn submit(info: web::Json<Info>) -> Result<String> {Ok(format!("Welcome {}!", info.username))
}

URL-encoded form

用于将表单数据提取成具体的数据类型。

rust">use actix_web::{post, web, App, HttpServer, Result};
use serde::Deserialize;#[derive(Deserialize)]
struct FormData {username: String,
}/// extract form data using serde
/// this handler gets called only if the content type is *x-www-form-urlencoded*
/// and the content of the request could be deserialized to a `FormData` struct
#[post("/")]
async fn index(form: web::Form<FormData>) -> Result<String> {Ok(format!("Welcome {}!", form.username))
}

涉及到更具体的可以参阅官方文档的Api Document

Actix Web架构摘要


总结

Actix Web 易用性高,性能出众,如果开发者想在生产环境中使用Rust做Http Server,其是值得一选的,在整体的开发框架中,State同步,提取和Connfigure 以及Handler的 布局设计是重要的。

“不论我们接受与否,一个不确定的时代已经到来”


http://www.ppmy.cn/news/1546077.html

相关文章

Unity Job System详解(5)——NativeHashSet/Map源码分析

不再贴完整源码&#xff0c;只贴关键部分源码 需要先看懂C# 字典原理 NativeHashSet的定义为&#xff1a; public unsafe struct NativeHashSet<T>: INativeDisposable, IEnumerable<T> where T : unmanaged, IEquatable<T> NativeHashMap的定义为&#…

gtfToGenePred如何下载

gtfToGenePred 是 UCSC 提供的一款工具&#xff0c;用于将 GTF&#xff08;Gene Transfer Format&#xff09;文件转换为 GenePred 格式的基因注释文件。由于不同的生物信息学分析工具对基因注释文件的格式要求不同&#xff0c;gtfToGenePred 的主要作用就是让 GTF 文件能够兼容…

linux系统中涉及到用户管理的命令知识

用户创建与密码设置 Linux中新建用户使用useradd命令&#xff0c;只有root用户才能执行&#xff0c;若useradd命令直接输入不管用&#xff0c;可使用绝对路径/usr/sbin/useradd。设置用户登录密码使用passwd命令。 su命令相关 su代表switch user&#xff0c;用于切换用户。切换…

开放寻址法、链式哈希数据结构详细解读

一、开放寻址法&#xff08;Open Addressing&#xff09; 1. 定义 开放寻址法是一种哈希冲突解决策略&#xff0c;所有元素都存储在哈希表中。当发生冲突时&#xff0c;即两个键计算出的哈希值相同时&#xff0c;会按照一定的探查序列查找下一个可用的位置来存储新元素。 2.…

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得 (二)

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得 &#xff08;二&#xff09; 一、前言 目前鸿蒙应用的实现逻辑&#xff0c;基本都是参考和移植Android端来实现。针对BLE低功耗蓝牙来说&#xff0c;在鸿蒙化的实现过程中。我们发现了&#xff0c;鸿蒙独有的优秀点&#xff0c…

机器学习3_支持向量机_线性不可分——MOOC

线性不可分的情况 如果训练样本是线性不可分的&#xff0c;那么上一节问题的是无解的&#xff0c;即不存在 和 满足上面所有N个限制条件。 对于线性不可分的情况&#xff0c;需要适当放松限制条件&#xff0c;使得问题有解。 放松限制条件的基本思路&#xff1a; 对每个训…

Codeforces Round 984 (Div. 3)

题目链接 A. Quintomania 题意 思路 模拟即可 示例代码 void solve() {int n;cin >> n;vector<int>arr(n);fer(i, 0 ,n) cin >> arr[i];fer(i, 1, n){if(abs(arr[i] - arr[i - 1]) ! 5 && abs(arr[i] - arr[i - 1]) ! 7){cout << "N…

信息安全工程师(78)网络安全应急响应技术与常见工具

前言 网络安全应急响应是指为应对网络安全事件&#xff0c;相关人员或组织机构对网络安全事件进行监测、预警、分析、响应和恢复等工作。 一、网络安全应急响应技术 网络安全应急响应组织 构成&#xff1a;网络安全应急响应组织主要由应急领导组和应急技术支撑组构成。领导组负…