Handler
请求处理程序可以是实现Handlertrait的任何对象 。
请求处理分两个阶段进行。首先调用handler对象,返回实现Responder特征的任何对象 。然后,respond_to()在返回的对象上调用,将自身转换为AsyncResult或Error.
默认情况下Actix提供对于一些标准类型的Responder实现,诸如&&'static str,String等
有关实现的完整列表,请查看 Responder文档。
有效Handler程序的示例:
fn index(req: HttpRequest) -> &'static str {"Hello world!"}
fn index(req: HttpRequest) -> String {"Hello world!".to_owned()}
如果涉及更复杂的类型,您还可以更改签名返回impl Responder。
fn index(req: HttpRequest) -> impl Responder {Bytes::from_static("Hello world!")}
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {...}
Handler特征是通用的通过S,它定义了应用程序状态的类型。可以使用该HttpRequest::state()方法从Handler访问应用程序状态; 但是,可以将状态作为只读引用进行访问。如果您需要对状态进行可变访问,则必须实现它。
注意:或者,Handler可以可变地访问其自己的状态,因为该handle方法对self进行了可变引用。请注意,actix会创建应用程序状态和处理程序的多个副本,这些副本对于每个线程都是唯一的。如果在多个线程中运行应用程序,actix将创建与应用程序状态对象和处理程序对象的线程数相同的数量。
以下是存储已处理请求数的处理程序示例:
use actix_web::{App, HttpRequest, HttpResponse, dev::Handler};struct MyHandler(usize);impl<S> Handler<S> for MyHandler {type Result = HttpResponse;/// Handle requestfn handle(&mut self, req: HttpRequest<S>) -> Self::Result {self.0 += 1;HttpResponse::Ok().into()}}
尽管此处理程序将起作用,但self.0根据线程数和每个线程处理的请求数将有所不同。一个适当的实现将使用Arc和AtomicUsize。
use actix_web::{server, App, HttpRequest, HttpResponse, dev::Handler};use std::sync::Arc;use std::sync::atomic::{AtomicUsize, Ordering};struct MyHandler(Arc<AtomicUsize>);impl<S> Handler<S> for MyHandler {type Result = HttpResponse;/// Handle requestfn handle(&mut self, req: HttpRequest<S>) -> Self::Result {self.0.fetch_add(1, Ordering::Relaxed);HttpResponse::Ok().into()}}fn main() {let sys = actix::System::new("example");let inc = Arc::new(AtomicUsize::new(0));server::new(move || {let cloned = inc.clone();App::new().resource("/", move |r| r.h(MyHandler(cloned)))}).bind("127.0.0.1:8088").unwrap().start();println!("Started http server: 127.0.0.1:8088");let _ = sys.run();}
小心使用Mutex或等同步原语RwLock。该actix-web框架异步处理请求。通过阻止线程执行,所有并发请求处理进程都将阻塞。如果需要从多个线程共享或更新某些状态,请考虑使用actix actor系统。
自定义响应类型
要直接从处理函数返回自定义类型,该类型需要实现Responder特征。
让我们为序列化为响应的自定义类型创建application/json响应:
# extern crate actix;# extern crate actix_web;extern crate serde;extern crate serde_json;#[macro_use] extern crate serde_derive;use actix_web::{server, App, HttpRequest, HttpResponse, Error, Responder, http};#[derive(Serialize)]struct MyObj {name: &'static str,}/// Responderimpl Responder for MyObj {type Item = HttpResponse;type Error = Error;fn respond_to<S>(self, req: &HttpRequest<S>) -> Result<HttpResponse, Error> {let body = serde_json::to_string(&self)?;// Create response and set content typeOk(HttpResponse::Ok().content_type("application/json").body(body))}}fn index(req: HttpRequest) -> impl Responder {MyObj { name: "user" }}fn main() {let sys = actix::System::new("example");server::new(|| App::new().resource("/", |r| r.method(http::Method::GET).f(index))).bind("127.0.0.1:8088").unwrap().start();println!("Started http server: 127.0.0.1:8088");let _ = sys.run();}
Async handlers
异步handlers
有两种不同类型的异步处理程序。响应对象可以异步生成,也可以更精确地生成任何实现Respondertrait的类型。
在这种情况下,handler程序必须返回一个Future解析为Responder类型的对象,即:
use actix_web::*;use bytes::Bytes;use futures::stream::once;use futures::future::{Future, result};fn index(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {result(Ok(HttpResponse::Ok().content_type("text/html").body(format!("Hello!")))).responder()}fn index2(req: &HttpRequest) -> Box<Future<Item=&'static str, Error=Error>> {result(Ok("Welcome!")).responder()}fn main() {App::new().resource("/async", |r| r.route().a(index)).resource("/", |r| r.route().a(index2)).finish();}
或者可以异步生成响应主体。在这种情况下,body必须实现流特征Stream<Item=Bytes, Error=Error>,即:
use actix_web::*;use bytes::Bytes;use futures::stream::once;fn index(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 main() {App::new().resource("/async", |r| r.f(index)).finish();}
两种方法都可以组合使用。(即与流体的异步响应)
这是可能的返回Result,其中Result::Item类型可以是Future。在此示例中,index处理程序可以立即返回错误或返回解析为a的future HttpResponse。
use actix_web::*;use bytes::Bytes;use futures::stream::once;use futures::future::{Future, result};fn index(req: &HttpRequest) -> Result<Box<Future<Item=HttpResponse, Error=Error>>, Error> {if is_error() {Err(error::ErrorBadRequest("bad request"))} else {Ok(Box::new(result(Ok(HttpResponse::Ok().content_type("text/html").body(format!("Hello!"))))))}}
不同的返回类型(Either)
有时,您需要返回不同类型的响应。例如,您可以进行错误检查并返回错误,返回异步响应或任何需要两种不同类型的结果。
对于这种情况,可以使用Either类型。 Either允许将两种不同的响应者类型组合成一种类型。
use futures::future::{Future, result};use actix_web::{Either, Error, HttpResponse};type RegisterResult = Either<HttpResponse, Box<Future<Item=HttpResponse, Error=Error>>>;fn index(req: &HttpRequest) -> impl Responder {if is_a_variant() { // <- choose variant AEither::A(HttpResponse::BadRequest().body("Bad data"))} else {Either::B( // <- variant Bresult(Ok(HttpResponse::Ok().content_type("text/html").body(format!("Hello!")))).responder())}}
