请求处理
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 str
、String
等。
已经实现
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!"))
}
}