mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-30 18:34:36 +01:00
more info for middleware guide
This commit is contained in:
parent
ffb5742b71
commit
b61a07a320
@ -1,8 +1,68 @@
|
|||||||
# Middlewares
|
# Middlewares
|
||||||
|
|
||||||
|
Actix middlewares system allows to add additional behaviour to request/response processing.
|
||||||
|
Middleware can hook into incomnig request process and modify request or halt request
|
||||||
|
processing and return response early. Also it can hook into response processing.
|
||||||
|
|
||||||
|
Typically middlewares involves in following actions:
|
||||||
|
|
||||||
|
* Pre-process the Request
|
||||||
|
* Post-process a Response
|
||||||
|
* Modify application state
|
||||||
|
* Access external services (redis, logging, sessions)
|
||||||
|
|
||||||
|
Middlewares are registered for each application and get executed in same order as
|
||||||
|
registraton order. In general, *middleware* is a type that implements
|
||||||
|
[*Middleware trait*](../actix_web/middlewares/trait.Middleware.html). Each method
|
||||||
|
in this trait has default implementation. Each method can return result immidietly
|
||||||
|
or *future* object.
|
||||||
|
|
||||||
|
Here is example of simple middleware that adds request and response headers:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate http;
|
||||||
|
# extern crate actix_web;
|
||||||
|
use http::{header, HttpTryFrom};
|
||||||
|
use actix_web::*;
|
||||||
|
use actix_web::middlewares::{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: &mut HttpRequest<S>) -> Started {
|
||||||
|
req.headers_mut().insert(
|
||||||
|
header::CONTENT_TYPE, header::HeaderValue::from_static("text/plain"));
|
||||||
|
Started::Done
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method is called when handler returns response,
|
||||||
|
/// but before sending http message to peer.
|
||||||
|
fn response(&self, req: &mut HttpRequest<S>, mut resp: HttpResponse) -> Response {
|
||||||
|
resp.headers_mut().insert(
|
||||||
|
header::HeaderName::try_from("X-VERSION").unwrap(),
|
||||||
|
header::HeaderValue::from_static("0.2"));
|
||||||
|
Response::Done(resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Application::new()
|
||||||
|
.middleware(Headers) // <- Register middleware, this method could be called multiple times
|
||||||
|
.resource("/", |r| r.h(httpcodes::HTTPOk));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Active provides several useful middlewares, like *logging*, *user sessions*, etc.
|
||||||
|
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|
||||||
Logging is implemented as middleware. Middlewares get executed in same order as registraton order.
|
Logging is implemented as middleware.
|
||||||
It is common to register logging middleware as first middleware for application.
|
It is common to register logging middleware as first middleware for application.
|
||||||
Logging middleware has to be registered for each application.
|
Logging middleware has to be registered for each application.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ Technically sync actors are worker style actors, multiple of them
|
|||||||
can be run in parallel and process messages from same queue (sync actors work in mpmc mode).
|
can be run in parallel and process messages from same queue (sync actors work in mpmc mode).
|
||||||
|
|
||||||
Let's create simple db api that can insert new user row into sqlite table.
|
Let's create simple db api that can insert new user row into sqlite table.
|
||||||
We need to define sync actor and connection that this actor will use. Same approach
|
We have to define sync actor and connection that this actor will use. Same approach
|
||||||
could used for other databases.
|
could used for other databases.
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
@ -24,14 +24,11 @@ impl Actor for DbExecutor {
|
|||||||
This is definition of our actor. Now we need to define *create user* message and response.
|
This is definition of our actor. Now we need to define *create user* message and response.
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(User, Error)]
|
||||||
struct CreateUser {
|
struct CreateUser {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseType for CreateUser {
|
|
||||||
type Item = models::User;
|
|
||||||
type Error = Error;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
We can send `CreateUser` message to `DbExecutor` actor, and as result we can get
|
We can send `CreateUser` message to `DbExecutor` actor, and as result we can get
|
||||||
@ -68,11 +65,11 @@ impl Handler<CreateUser> for DbExecutor {
|
|||||||
```
|
```
|
||||||
|
|
||||||
That is it. Now we can use *DbExecutor* actor from any http handler or middleware.
|
That is it. Now we can use *DbExecutor* actor from any http handler or middleware.
|
||||||
All we need is to start *DbExecutor* actors and store address in state where http handler
|
All we need is to start *DbExecutor* actors and store address in a state where http handler
|
||||||
can access it.
|
can access it.
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
/// This is state where we sill store *DbExecutor* address.
|
/// This is state where we store *DbExecutor* address.
|
||||||
struct State {
|
struct State {
|
||||||
db: SyncAddress<DbExecutor>,
|
db: SyncAddress<DbExecutor>,
|
||||||
}
|
}
|
||||||
@ -97,7 +94,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
And finally we can use this state in handler function. We get message response
|
And finally we can use this state in a requst handler. We get message response
|
||||||
asynchronously, so handler needs to return future object, also `Route::a()` needs to be
|
asynchronously, so handler needs to return future object, also `Route::a()` needs to be
|
||||||
used for async handler registration.
|
used for async handler registration.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user