请求处理

handlers.md
commit - 4d8d53cea59bca095ca5c02ef81f0b1791736855 - 2020.09.12

请求 handler 是异步函数,它接受零个或多个参数,这些参数可以从请求中提取(即实现了 FromRequest trait,参见 impl FromRequest),并返回可以转换为 HttpResponse 的类型(即实现了 Responder trait,参见impl Responder)。

请求处理分为两个阶段。

  • 首先,调用 handler 对象,返回实现了 Responder trait 的任何对象。
  • 然后,对返回的对象调用 respond_to() 方法,将其自身转换为 HttpResponse 或者 Error

默认情况下,actix-web 为一些标准类型提供了 Responder trait 实现。例如,&'static strString 等。

已经实现 Responder trait 的类型,其完整清单请参见 Responder 文档

合法的请求 handler 示例:

async fn index(_req: HttpRequest) -> &'static str {
    "Hello world!"
}
async fn index(_req: HttpRequest) -> String {
    "Hello world!".to_owned()
}

如果涉及到更复杂的类型,你还可以更改签名以返回比较好用的 impl Responder(实现 Responder trait)。

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

响应自定义类型

要直接从 handler 函数返回自定义类型,则该类型需要实现 Responder trait。

让我们为一个自定义类型创建响应,该类型将序列化为 application/json 响应:

use actix_web::{Error, HttpRequest, HttpResponse, Responder};
use serde::Serialize;
use futures::future::{ready, Ready};

#[derive(Serialize)]
struct MyObj {
    name: &'static str,
}

// Responder
impl Responder for MyObj {
    type Error = Error;
    type Future = Ready<Result<HttpResponse, Error>>;

    fn respond_to(self, _req: &HttpRequest) -> Self::Future {
        let body = serde_json::to_string(&self).unwrap();

        // Create response and set content type
        ready(Ok(HttpResponse::Ok()
            .content_type("application/json")
            .body(body)))
    }
}

async fn index() -> impl Responder {
    MyObj { name: "user" }
}

流式响应体(body)

响应体可以异步生成。下述实例中,主体(body)必须实现 stream trait Stream<Item=Bytes, Error=Error>,即:

use actix_web::{get, App, Error, HttpResponse, HttpServer};
use bytes::Bytes;
use futures::future::ok;
use futures::stream::once;

#[get("/stream")]
async fn stream() -> HttpResponse {
    let body = once(ok::<_, Error>(Bytes::from_static(b"test")));

    HttpResponse::Ok()
        .content_type("application/json")
        .streaming(body)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().service(stream))
        .bind("127.0.0.1:8080")?
        .run()
        .await
}

差异化返回类型(Either 枚举)

有时,你需要返回不同类型的响应。比如,你可以检查错误和返回错误:返回错误的异步响应,或者返回依赖于两个不同类型的任意结果(result)。

下述实例中,可以使用 Either 枚举类型,Either 允许将两种不同的响应类型组合成单一类型。

use actix_web::{Either, Error, HttpResponse};

type RegisterResult = Either<HttpResponse, Result<&'static str, Error>>;

async fn index() -> RegisterResult {
    if is_a_variant() {
        // <- choose variant A
        Either::A(HttpResponse::BadRequest().body("Bad data"))
    } else {
        // <- variant B
        Either::B(Ok("Hello!"))
    }
}