重庆 机械有限公司 江北网站建设百度空间登录入口
Actix-web 学习
请求处理分为两个阶段。
首先调用处理程序对象,返回实现Responder trait的任何对象。
然后,在返回的对象上调用respond_to(),将其自身转换为AsyncResult或Error。
默认情况下,actix为一些标准类型提供响应器实现,比如静态str、字符串等。要查看完整的实现列表,请查看响应器文档。
基础的Demo
extern crate actix_web;
extern crate futures;use actix_web::{server, App, HttpRequest, Responder, HttpResponse, Body};
use std::cell::Cell;
use std::io::Error;
use futures::future::{Future, result};
use futures::stream::once;
use bytes::Bytes;struct AppState {counter: Cell<usize>,
}// 有状态
fn index2(req: &HttpRequest<AppState>) -> String {let count = req.state().counter.get() + 1; // <- get countreq.state().counter.set(count); // <- store new count in stateformat!("Request number: {}", count) // <- response with count
}// 静态文本
fn index1(_req: &HttpRequest) -> impl Responder {"Hello world!"
}fn index11(_req: &HttpRequest) -> &'static str {"Hello world!"
}// 异步内容
fn index12(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {result(Ok(HttpResponse::Ok().content_type("text/html").body(format!("Hello!")))).responder()
}fn index13(req: &HttpRequest) -> Box<Future<Item=&'static str, Error=Error>> {result(Ok("Welcome!")).responder()
}fn index14(req: &HttpRequest) -> HttpResponse {let body = once(Ok(Bytes::from_static(b"test")));HttpResponse::Ok().content_type("application/json").body(Body::Streaming(Box::new(body)))
}// 文件
// fn f1(req: &HttpRequest) -> io::Result<fs::NamedFile> {
// Ok(fs::NamedFile::open("static/index.html")?)
// }fn main() {let addr = "0.0.0.0:8888";let s = server::new(|| {vec![App::new().prefix("/app1").resource("/", |r| r.f(index1)).resource("/2", |r| r.f(index11)).resource("/3", |r| r.f(index12)).resource("/4", |r| r.f(index13)).resource("/5", |r| r.f(index14)).boxed(),App::with_state(AppState { counter: Cell::new(0) }).prefix("/app2").resource("/", |r| r.f(index2)).boxed(),]}).bind(addr).unwrap();println!("server run: {}", addr);s.run();
}
请求内容解析
extern crate actix_web;
extern crate futures;
#[macro_use]
extern crate serde_derive;use actix_web::*;
use std::cell::Cell;
use std::io::Error;
use futures::future::{Future, result};
use futures::stream::once;
use bytes::Bytes;// url 解析
#[derive(Debug, Serialize, Deserialize)]
struct Info {userid: u32,friend: String,
}fn index(info: Path<Info>) -> String {format!("Welcome {}!", info.friend)
}fn index2(info: Path<(u32, String)>) -> Result<String> {Ok(format!("Welcome {}! {}", info.1, info.0))
}// url 参数解析
fn index3(info: Query<Info>) -> String {format!("Welcome {} {}", info.userid, info.friend)
}// body json 解析
fn index4(info: Json<Info>) -> Result<String> {Ok(format!("Welcome {} {}", info.userid, info.friend))
}// body form 解析
fn index5(form: Form<Info>) -> Result<String> {Ok(format!("Welcome {}!", form.userid))
}// json 手动解析1
fn index6(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {req.json().from_err().and_then(|val: Info| {println!("model: {:?}", val);Ok(HttpResponse::Ok().json(val)) // <- send response}).responder()
}// Json手动解析2, 手动处理body
fn index7(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {// `concat2` will asynchronously read each chunk of the request body and// return a single, concatenated, chunkreq.concat2()// `Future::from_err` acts like `?` in that it coerces the error type from// the future into the final error type.from_err()// `Future::and_then` can be used to merge an asynchronous workflow with a// synchronous workflow.and_then(|body| {let obj = serde_json::from_slice::<Info>(&body)?;Ok(HttpResponse::Ok().json(obj))}).responder()
}// multipart
//fn index8(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {get multipart and iterate over multipart items
// req.multipart()
// .and_then(|item| {
// match item {
// multipart::MultipartItem::Field(field) => {
// println!("==== FIELD ==== {:?} {:?}",
// field.headers(),
// field.content_type());
// Either::A(
// field.map(|chunk| {
// println!("-- CHUNK: \n{}",
// std::str::from_utf8(&chunk).unwrap());
// })
// .fold((), |_, _| result(Ok(()))))
// }
// multipart::MultipartItem::Nested(mp) => {
// Either::B(result(Ok(())))
// }
// }
// })
// ...
// // https://github.com/actix/examples/tree/master/multipart/
//}// stream
//fn index9(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
// req
// .payload()
// .from_err()
// .fold((), |_, chunk| {
// println!("Chunk: {:?}", chunk);
// result::<_, error::PayloadError>(Ok(()))
// })
// .map(|_| HttpResponse::Ok().finish())
// .responder()
//}// 通用解析
// fn index(req: &HttpRequest) -> HttpResponse {
// let params = Path::<(String, String)>::extract(req);
// let info = Json::<MyInfo>::extract(req); // ...
// }fn main() {let addr = "0.0.0.0:8888";let s = server::new(|| {vec![App::new().prefix("/args").resource("/1/{userid}/{friend}", |r| r.method(http::Method::GET).with(index)).resource("/2/{userid}/{friend}", |r| r.with(index2)).route("/3", http::Method::GET, index3).route("/4", http::Method::POST, index4).route("/5", http::Method::POST, index5).boxed(),]}).bind(addr).unwrap();println!("server run: {}", addr);s.run();
}
Static
extern crate actix_web;use actix_web::{App};
use actix_web::fs::{StaticFileConfig, StaticFiles};#[derive(Default)]
struct MyConfig;impl StaticFileConfig for MyConfig {fn is_use_etag() -> bool {false}fn is_use_last_modifier() -> bool {false}
}fn main() {App::new().handler("/static",StaticFiles::with_config(".", MyConfig).unwrap().show_files_listing()).finish();
}
Websocket
use actix::*;
use actix_web::*;/// Define http actor
struct Ws;impl Actor for Ws {type Context = ws::WebsocketContext<Self>;
}/// Handler for ws::Message message
impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {match msg {ws::Message::Ping(msg) => ctx.pong(&msg),ws::Message::Text(text) => ctx.text(text),ws::Message::Binary(bin) => ctx.binary(bin),_ => (),}}
}fn main() {App::new().resource("/ws/", |r| r.f(|req| ws::start(req, Ws))).finish();
}
middleware
用到了再说
https://actix.rs/docs/middleware/