1
0
mirror of https://github.com/actix/actix-website synced 2025-06-29 08:14:58 +02:00

First pass at Middlewares.

This commit is contained in:
Cameron Dershem
2019-06-17 16:57:57 -04:00
parent 083522ef19
commit 9a16b6db93
8 changed files with 189 additions and 125 deletions

View File

@ -21,48 +21,14 @@ Typically, middleware is involved in the following actions:
Middleware is registered for each application and executed in same order as
registration. In general, a *middleware* is a type that implements the
[*Middleware trait*](../../actix-web/actix_web/middleware/trait.Middleware.html).
Each method in this trait has a default implementation. Each method can return
[*Service trait*](../../actix-web/actix_web/dev/trait.Service.html) and
[*Transform trait*](../../actix-web/actix_web/dev/trait.Transform.html).
Each method in the traits has a default implementation. Each method can return
a result immediately or a *future* object.
The following demonstrates using middleware to add request and response headers:
The following demonstrates creating a simple middleware:
```rust
use http::{header, HttpTryFrom};
use actix_web::{App, HttpRequest, HttpResponse, Result};
use actix_web::middleware::{Middleware, Started, Response};
struct Headers; // <- Our middleware
/// Middleware implementation, middlewares are generic over application state,
/// so you can access state with `HttpRequest::state()` method.
impl<S> Middleware<S> for Headers {
/// Method is called when request is ready. It may return
/// future, which should resolve before next middleware get called.
fn start(&self, req: &HttpRequest<S>) -> Result<Started> {
Ok(Started::Done)
}
/// Method is called when handler returns response,
/// but before sending http message to peer.
fn response(&self, req: &HttpRequest<S>, mut resp: HttpResponse)
-> Result<Response>
{
resp.headers_mut().insert(
header::HeaderName::try_from("X-VERSION").unwrap(),
header::HeaderValue::from_static("0.2"));
Ok(Response::Done(resp))
}
}
fn main() {
App::new()
// Register middleware, this method can be called multiple times
.middleware(Headers)
.resource("/", |r| r.f(|_| HttpResponse::Ok()));
}
```
{{< include-example example="middleware" file="main.rs" section="main" >}}
> Actix provides several useful middlewares, such as *logging*, *user sessions*, etc.
@ -85,21 +51,7 @@ Default `Logger` can be created with `default` method, it uses the default forma
%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
```
```rust
extern crate env_logger;
use actix_web::App;
use actix_web::middleware::Logger;
fn main() {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
App::new()
.middleware(Logger::default())
.middleware(Logger::new("%a %{User-Agent}i"))
.finish();
}
```
{{< include-example example="middleware" file="logger.rs" section="logger" >}}
The following is an example of the default logging format:
@ -140,37 +92,23 @@ To set default response headers, the `DefaultHeaders` middleware can be used. Th
*DefaultHeaders* middleware does not set the header if response headers already contain
a specified header.
```rust
use actix_web::{http, middleware, App, HttpResponse};
fn main() {
let app = App::new()
.middleware(
middleware::DefaultHeaders::new()
.header("X-Version", "0.2"))
.resource("/test", |r| {
r.method(http::Method::GET).f(|req| HttpResponse::Ok());
r.method(http::Method::HEAD).f(|req| HttpResponse::MethodNotAllowed());
})
.finish();
}
```
{{< include-example example="middleware" file="default_headers.rs" section="default-headers" >}}
## User sessions
Actix provides a general solution for session management. The
[**SessionStorage**](../../actix-web/actix_web/middleware/session/struct.SessionStorage.html) middleware can be
[**actix-session**](https://docs.rs/actix-session/0.1.1/actix_session/) middleware can be
used with different backend types to store session data in different backends.
> By default, only cookie session backend is implemented. Other backend implementations
> can be added.
[**CookieSessionBackend**](../../actix-web/actix_web/middleware/session/struct.CookieSessionBackend.html)
[**CookieSession**](../../actix-web/actix_web/middleware/session/struct.CookieSessionBackend.html)
uses cookies as session storage. `CookieSessionBackend` creates sessions which
are limited to storing fewer than 4000 bytes of data, as the payload must fit into a
single cookie. An internal server error is generated if a session contains more than 4000 bytes.
A cookie may have a security policy of *signed* or *private*. Each has a respective `CookieSessionBackend` constructor.
A cookie may have a security policy of *signed* or *private*. Each has a respective `CookieSession` constructor.
A *signed* cookie may be viewed but not modified by the client. A *private* cookie may neither be viewed nor modified by the client.
@ -178,41 +116,13 @@ The constructors take a key as an argument. This is the private key for cookie s
In general, you create a
`SessionStorage` middleware and initialize it with specific backend implementation,
such as a `CookieSessionBackend`. To access session data,
such as a `CookieSession`. To access session data,
[*HttpRequest::session()*](../../actix-web/actix_web/middleware/session/trait.RequestSession.html#tymethod.session)
must be used. This method returns a
[*Session*](../../actix-web/actix_web/middleware/session/struct.Session.html) object, which allows us to get or set
session data.
```rust
use actix_web::{server, App, HttpRequest, Result};
use actix_web::middleware::session::{RequestSession, SessionStorage, CookieSessionBackend};
fn index(req: &HttpRequest) -> Result<&'static str> {
// access session data
if let Some(count) = req.session().get::<i32>("counter")? {
println!("SESSION value: {}", count);
req.session().set("counter", count+1)?;
} else {
req.session().set("counter", 1)?;
}
Ok("Welcome!")
}
fn main() {
let sys = actix::System::new("basic-example");
server::new(
|| App::new().middleware(
SessionStorage::new(
CookieSessionBackend::signed(&[0; 32])
.secure(false)
)))
.bind("127.0.0.1:59880").unwrap()
.start();
let _ = sys.run();
}
```
{{< include-example example="middleware" file="user_sessions.rs" section="user-session" >}}
# Error handlers
@ -223,26 +133,4 @@ for a specific status code. You can modify an existing response or create a comp
one. The error handler can return a response immediately or return a future that resolves
into a response.
```rust
use actix_web::{
App, HttpRequest, HttpResponse, Result,
http, middleware::Response, middleware::ErrorHandlers};
fn render_500<S>(_: &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();
}
```
{{< include-example example="middleware" file="errorhandler.rs" section="error-handler" >}}