Handler

请求处理程序可以是实现Handlertrait的任何对象 。

请求处理分两个阶段进行。首先调用handler对象,返回实现Responder特征的任何对象 。然后,respond_to()在返回的对象上调用,将自身转换为AsyncResultError.

默认情况下Actix提供对于一些标准类型的Responder实现,诸如&&'static strString

有关实现的完整列表,请查看 Responder文档。

有效Handler程序的示例:

  1. fn index(req: HttpRequest) -> &'static str {
  2. "Hello world!"
  3. }
  1. fn index(req: HttpRequest) -> String {
  2. "Hello world!".to_owned()
  3. }

如果涉及更复杂的类型,您还可以更改签名返回impl Responder

  1. fn index(req: HttpRequest) -> impl Responder {
  2. Bytes::from_static("Hello world!")
  3. }
  1. fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
  2. ...
  3. }

Handler特征是通用的通过S,它定义了应用程序状态的类型。可以使用该HttpRequest::state()方法从Handler访问应用程序状态; 但是,可以将状态作为只读引用进行访问。如果您需要对状态进行可变访问,则必须实现它。

注意:或者,Handler可以可变地访问其自己的状态,因为该handle方法对self进行了可变引用。请注意,actix会创建应用程序状态和处理程序的多个副本,这些副本对于每个线程都是唯一的。如果在多个线程中运行应用程序,actix将创建与应用程序状态对象和处理程序对象的线程数相同的数量。

以下是存储已处理请求数的处理程序示例:

  1. use actix_web::{App, HttpRequest, HttpResponse, dev::Handler};
  2. struct MyHandler(usize);
  3. impl<S> Handler<S> for MyHandler {
  4. type Result = HttpResponse;
  5. /// Handle request
  6. fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
  7. self.0 += 1;
  8. HttpResponse::Ok().into()
  9. }
  10. }

尽管此处理程序将起作用,但self.0根据线程数和每个线程处理的请求数将有所不同。一个适当的实现将使用ArcAtomicUsize

  1. use actix_web::{server, App, HttpRequest, HttpResponse, dev::Handler};
  2. use std::sync::Arc;
  3. use std::sync::atomic::{AtomicUsize, Ordering};
  4. struct MyHandler(Arc<AtomicUsize>);
  5. impl<S> Handler<S> for MyHandler {
  6. type Result = HttpResponse;
  7. /// Handle request
  8. fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
  9. self.0.fetch_add(1, Ordering::Relaxed);
  10. HttpResponse::Ok().into()
  11. }
  12. }
  13. fn main() {
  14. let sys = actix::System::new("example");
  15. let inc = Arc::new(AtomicUsize::new(0));
  16. server::new(
  17. move || {
  18. let cloned = inc.clone();
  19. App::new()
  20. .resource("/", move |r| r.h(MyHandler(cloned)))
  21. })
  22. .bind("127.0.0.1:8088").unwrap()
  23. .start();
  24. println!("Started http server: 127.0.0.1:8088");
  25. let _ = sys.run();
  26. }

小心使用Mutex或等同步原语RwLock。该actix-web框架异步处理请求。通过阻止线程执行,所有并发请求处理进程都将阻塞。如果需要从多个线程共享或更新某些状态,请考虑使用actix actor系统。

自定义响应类型

要直接从处理函数返回自定义类型,该类型需要实现Responder特征。

让我们为序列化为响应的自定义类型创建application/json响应:

  1. # extern crate actix;
  2. # extern crate actix_web;
  3. extern crate serde;
  4. extern crate serde_json;
  5. #[macro_use] extern crate serde_derive;
  6. use actix_web::{server, App, HttpRequest, HttpResponse, Error, Responder, http};
  7. #[derive(Serialize)]
  8. struct MyObj {
  9. name: &'static str,
  10. }
  11. /// Responder
  12. impl Responder for MyObj {
  13. type Item = HttpResponse;
  14. type Error = Error;
  15. fn respond_to<S>(self, req: &HttpRequest<S>) -> Result<HttpResponse, Error> {
  16. let body = serde_json::to_string(&self)?;
  17. // Create response and set content type
  18. Ok(HttpResponse::Ok()
  19. .content_type("application/json")
  20. .body(body))
  21. }
  22. }
  23. fn index(req: HttpRequest) -> impl Responder {
  24. MyObj { name: "user" }
  25. }
  26. fn main() {
  27. let sys = actix::System::new("example");
  28. server::new(
  29. || App::new()
  30. .resource("/", |r| r.method(http::Method::GET).f(index)))
  31. .bind("127.0.0.1:8088").unwrap()
  32. .start();
  33. println!("Started http server: 127.0.0.1:8088");
  34. let _ = sys.run();
  35. }

Async handlers

异步handlers

有两种不同类型的异步处理程序。响应对象可以异步生成,也可以更精确地生成任何实现Respondertrait的类型。

在这种情况下,handler程序必须返回一个Future解析为Responder类型的对象,即:

  1. use actix_web::*;
  2. use bytes::Bytes;
  3. use futures::stream::once;
  4. use futures::future::{Future, result};
  5. fn index(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
  6. result(Ok(HttpResponse::Ok()
  7. .content_type("text/html")
  8. .body(format!("Hello!"))))
  9. .responder()
  10. }
  11. fn index2(req: &HttpRequest) -> Box<Future<Item=&'static str, Error=Error>> {
  12. result(Ok("Welcome!"))
  13. .responder()
  14. }
  15. fn main() {
  16. App::new()
  17. .resource("/async", |r| r.route().a(index))
  18. .resource("/", |r| r.route().a(index2))
  19. .finish();
  20. }

或者可以异步生成响应主体。在这种情况下,body必须实现流特征Stream<Item=Bytes, Error=Error>,即:

  1. use actix_web::*;
  2. use bytes::Bytes;
  3. use futures::stream::once;
  4. fn index(req: &HttpRequest) -> HttpResponse {
  5. let body = once(Ok(Bytes::from_static(b"test")));
  6. HttpResponse::Ok()
  7. .content_type("application/json")
  8. .body(Body::Streaming(Box::new(body)))
  9. }
  10. fn main() {
  11. App::new()
  12. .resource("/async", |r| r.f(index))
  13. .finish();
  14. }

两种方法都可以组合使用。(即与流体的异步响应)

这是可能的返回Result,其中Result::Item类型可以是Future。在此示例中,index处理程序可以立即返回错误或返回解析为a的future HttpResponse

  1. use actix_web::*;
  2. use bytes::Bytes;
  3. use futures::stream::once;
  4. use futures::future::{Future, result};
  5. fn index(req: &HttpRequest) -> Result<Box<Future<Item=HttpResponse, Error=Error>>, Error> {
  6. if is_error() {
  7. Err(error::ErrorBadRequest("bad request"))
  8. } else {
  9. Ok(Box::new(
  10. result(Ok(HttpResponse::Ok()
  11. .content_type("text/html")
  12. .body(format!("Hello!"))))))
  13. }
  14. }

不同的返回类型(Either)

有时,您需要返回不同类型的响应。例如,您可以进行错误检查并返回错误,返回异步响应或任何需要两种不同类型的结果。

对于这种情况,可以使用Either类型。 Either允许将两种不同的响应者类型组合成一种类型。

  1. use futures::future::{Future, result};
  2. use actix_web::{Either, Error, HttpResponse};
  3. type RegisterResult = Either<HttpResponse, Box<Future<Item=HttpResponse, Error=Error>>>;
  4. fn index(req: &HttpRequest) -> impl Responder {
  5. if is_a_variant() { // <- choose variant A
  6. Either::A(
  7. HttpResponse::BadRequest().body("Bad data"))
  8. } else {
  9. Either::B( // <- variant B
  10. result(Ok(HttpResponse::Ok()
  11. .content_type("text/html")
  12. .body(format!("Hello!")))).responder())
  13. }
  14. }