1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-28 01:52:57 +01:00

add ErrorHandlers middleware

This commit is contained in:
Nikolay Kim 2018-04-02 21:37:00 -07:00
parent d292c5023f
commit 3b93bff602
3 changed files with 151 additions and 0 deletions

View File

@ -210,3 +210,37 @@ fn main() {
# let _ = sys.run(); # let _ = sys.run();
} }
``` ```
## Error handlers
`ErrorHandlers` middleware allows to provide custom handlers for responses.
You can use `ErrorHandlers::handler()` method to register a custom error handler
for specific status code. You can modify existing response or create completly new
one. Error handler can return response immediately or return future that resolves
to a response.
```rust
# extern crate actix_web;
use actix_web::{
App, HttpRequest, HttpResponse, Result,
http, middleware::Response, middleware::ErrorHandlers};
fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
let mut builder = resp.into_builder();
builder.header(http::header::CONTENT_TYPE, "application/json");
Ok(Response::Done(builder.into()))
}
fn main() {
let app = App::new()
.middleware(
ErrorHandlers::new()
.handler(http::StatusCode::INTERNAL_SERVER_ERROR, render_500))
.resource("/test", |r| {
r.method(http::Method::GET).f(|_| HttpResponse::Ok());
r.method(http::Method::HEAD).f(|_| HttpResponse::MethodNotAllowed());
})
.finish();
}
```

View File

@ -0,0 +1,115 @@
use std::collections::HashMap;
use error::Result;
use http::StatusCode;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::{Middleware, Response};
type ErrorHandler<S> = Fn(&mut HttpRequest<S>, HttpResponse) -> Result<Response>;
/// `Middleware` for allowing custom handlers for responses.
///
/// You can use `ErrorHandlers::handler()` method to register a custom error handler
/// for specific status code. You can modify existing response or create completly new
/// one.
///
/// ## Example
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::{
/// App, HttpRequest, HttpResponse, Result,
/// http, middleware::Response, middleware::ErrorHandlers};
///
/// fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
/// let mut builder = resp.into_builder();
/// builder.header(http::header::CONTENT_TYPE, "application/json");
/// Ok(Response::Done(builder.into()))
/// }
///
/// fn main() {
/// let app = App::new()
/// .middleware(
/// ErrorHandlers::new()
/// .handler(http::StatusCode::INTERNAL_SERVER_ERROR, render_500))
/// .resource("/test", |r| {
/// r.method(http::Method::GET).f(|_| HttpResponse::Ok());
/// r.method(http::Method::HEAD).f(|_| HttpResponse::MethodNotAllowed());
/// })
/// .finish();
/// }
/// ```
pub struct ErrorHandlers<S> {
handlers: HashMap<StatusCode, Box<ErrorHandler<S>>>,
}
impl<S> Default for ErrorHandlers<S> {
fn default() -> Self {
ErrorHandlers {
handlers: HashMap::new(),
}
}
}
impl<S> ErrorHandlers<S> {
/// Construct new `ErrorHandlers` instance
pub fn new() -> Self {
ErrorHandlers::default()
}
/// Register error handler for specified status code
pub fn handler<F>(mut self, status: StatusCode, handler: F) -> Self
where F: Fn(&mut HttpRequest<S>, HttpResponse) -> Result<Response> + 'static
{
self.handlers.insert(status, Box::new(handler));
self
}
}
impl<S: 'static> Middleware<S> for ErrorHandlers<S> {
fn response(&self, req: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
if let Some(handler) = self.handlers.get(&resp.status()) {
handler(req, resp)
} else {
Ok(Response::Done(resp))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use http::StatusCode;
use http::header::CONTENT_TYPE;
fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
let mut builder = resp.into_builder();
builder.header(CONTENT_TYPE, "0001");
Ok(Response::Done(builder.into()))
}
#[test]
fn test_handler() {
let mw = ErrorHandlers::new()
.handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
let mut req = HttpRequest::default();
let resp = HttpResponse::InternalServerError().finish();
let resp = match mw.response(&mut req, resp) {
Ok(Response::Done(resp)) => resp,
_ => panic!(),
};
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
let resp = HttpResponse::Ok().finish();
let resp = match mw.response(&mut req, resp) {
Ok(Response::Done(resp)) => resp,
_ => panic!(),
};
assert!(!resp.headers().contains_key(CONTENT_TYPE));
}
}

View File

@ -10,9 +10,11 @@ mod logger;
#[cfg(feature = "session")] #[cfg(feature = "session")]
mod session; mod session;
mod defaultheaders; mod defaultheaders;
mod errhandlers;
pub mod cors; pub mod cors;
pub mod csrf; pub mod csrf;
pub use self::logger::Logger; pub use self::logger::Logger;
pub use self::errhandlers::ErrorHandlers;
pub use self::defaultheaders::{DefaultHeaders, DefaultHeadersBuilder}; pub use self::defaultheaders::{DefaultHeaders, DefaultHeadersBuilder};
#[cfg(feature = "session")] #[cfg(feature = "session")]