1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-25 00:12:59 +01:00
actix-extras/guide/src/qs_7.md

270 lines
8.4 KiB
Markdown
Raw Normal View History

# Request & Response
2017-12-02 20:41:20 +01:00
2017-12-05 05:38:38 +01:00
## Response
Builder-like patter is used to construct an instance of `HttpResponse`.
`HttpResponse` provides several method that returns `HttpResponseBuilder` instance,
which is implements various convinience methods that helps build response.
Check [documentation](../actix_web/dev/struct.HttpResponseBuilder.html)
for type description. Methods `.body`, `.finish`, `.json` finalizes response creation,
if this methods get call for the same builder instance, builder will panic.
```rust
# extern crate actix_web;
use actix_web::*;
2017-12-08 01:40:29 +01:00
use actix_web::headers::ContentEncoding;
2017-12-05 05:38:38 +01:00
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Br)
.content_type("plain/text")
.header("X-Hdr", "sample")
.body("data").unwrap()
}
# fn main() {}
```
2017-12-02 20:41:20 +01:00
## Content encoding
2017-12-05 05:38:38 +01:00
Actix automatically *compress*/*decompress* payload. Following codecs are supported:
2017-12-02 20:41:20 +01:00
* Brotli
* Gzip
* Deflate
* Identity
If request headers contains `Content-Encoding` header, request payload get decompressed
according to header value. Multiple codecs are not supported, i.e: `Content-Encoding: br, gzip`.
2017-12-04 05:09:46 +01:00
Response payload get compressed based on *content_encoding* parameter.
By default `ContentEncoding::Auto` is used. If `ContentEncoding::Auto` is selected
then compression depends on request's `Accept-Encoding` header.
`ContentEncoding::Identity` could be used to disable compression.
If other content encoding is selected the compression is enforced for this codec. For example,
to enable `brotli` response's body compression use `ContentEncoding::Br`:
```rust
2017-12-05 01:26:40 +01:00
# extern crate actix_web;
2017-12-04 05:09:46 +01:00
use actix_web::*;
2017-12-08 01:40:29 +01:00
use actix_web::headers::ContentEncoding;
2017-12-04 03:58:15 +01:00
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Br)
2017-12-04 05:09:46 +01:00
.body("data").unwrap()
2017-12-04 03:58:15 +01:00
}
2017-12-04 05:09:46 +01:00
# fn main() {}
2017-12-04 03:58:15 +01:00
```
2017-12-21 00:12:43 +01:00
## JSON Request
Unfortunately, because of async nature of actix web framework, deserializing json
requests is not very ergonomic process. First you need to load whole body into
temporal storage and only then you can deserialize it.
Here is simple example. We will deserialize *MyObj* struct.
```rust,ignore
#[derive(Debug, Deserialize)]
struct MyObj {
name: String,
number: i32,
}
```
We need to load request body first.
```rust,ignore
fn index(mut req: HttpRequest) -> Future<Item=HttpResponse, Error=Error> {
req.payload_mut().readany()
.fold(BytesMut::new(), |mut body, chunk| { // <- load request body
body.extend(chunk);
result::<_, error::PayloadError>(Ok(body))
})
.and_then(|body| { // <- body is loaded, now we can deserialize json
let obj = serde_json::from_slice::<MyObj>(&body).unwrap();
println!("MODEL: {:?}", obj); // <- do something with payload
ok(httpcodes::HTTPOk.response()) // <- send response
})
}
```
Full example is available in
[examples directory](https://github.com/actix/actix-web/tree/master/examples/json/).
2017-12-04 03:51:52 +01:00
## JSON Response
The `Json` type allows you to respond with well-formed JSON data: simply return a value of
type Json<T> where T is the type of a structure to serialize into *JSON*. The
type `T` must implement the `Serialize` trait from *serde*.
```rust
2017-12-05 01:26:40 +01:00
# extern crate actix_web;
2017-12-04 03:51:52 +01:00
#[macro_use] extern crate serde_derive;
use actix_web::*;
#[derive(Serialize)]
struct MyObj {
name: String,
}
fn index(req: HttpRequest) -> Result<Json<MyObj>> {
Ok(Json(MyObj{name: req.match_info().query("name")?}))
}
fn main() {
Application::new()
.resource(r"/a/{name}", |r| r.method(Method::GET).f(index))
2017-12-04 03:51:52 +01:00
.finish();
}
```
2017-12-14 07:36:28 +01:00
## Chunked transfer encoding
Actix automatically decode *chunked* encoding. `HttpRequest::payload()` already contains
decoded bytes stream. If request payload compressed with one of supported
compression codecs (br, gzip, deflate) bytes stream get decompressed.
Chunked encoding on response could be enabled with `HttpResponseBuilder::chunked()` method.
But this takes effect only for `Body::Streaming(BodyStream)` or `Body::StreamingContext` bodies.
Also if response payload compression is enabled and streaming body is used, chunked encoding
get enabled automatically.
Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
```rust
# extern crate actix_web;
use actix_web::*;
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.chunked()
2017-12-19 09:18:57 +01:00
.body(Body::Streaming(payload::Payload::empty().stream())).unwrap()
2017-12-14 07:36:28 +01:00
}
# fn main() {}
```
## Cookies
[WIP]
## Multipart body
2017-12-19 19:10:03 +01:00
Actix provides multipart stream support.
[*Multipart*](../actix_web/multipart/struct.Multipart.html) is implemented as
a stream of multipart items, each item could be
[*Field*](../actix_web/multipart/struct.Field.html) or nested *Multipart* stream.
`HttpResponse::multipart()` method returns *Multipart* stream for current request.
2017-12-19 18:55:49 +01:00
2017-12-19 19:10:03 +01:00
In simple form multipart stream handling could be implemented similar to this example
2017-12-19 18:55:49 +01:00
2017-12-19 19:10:03 +01:00
```rust,ignore
# extern crate actix_web;
use actix_web::*;
fn index(req: HttpRequest) -> Box<Future<...>> {
req.multipart() // <- get multipart stream for current request
.and_then(|item| { // <- iterate over multipart items
match item {
// Handle multipart Field
multipart::MultipartItem::Field(field) => {
println!("==== FIELD ==== {:?} {:?}", field.heders(), field.content_type());
Either::A(
// Field in turn is a stream of *Bytes* objects
field.map(|chunk| {
println!("-- CHUNK: \n{}",
std::str::from_utf8(&chunk).unwrap());})
.fold((), |_, _| result(Ok(()))))
},
multipart::MultipartItem::Nested(mp) => {
// Or item could be nested Multipart stream
Either::B(result(Ok(())))
}
}
})
}
```
Full example is available in
[examples directory](https://github.com/actix/actix-web/tree/master/examples/multipart/).
2017-12-14 07:36:28 +01:00
## Urlencoded body
2017-12-19 23:03:01 +01:00
Actix provides support for *application/x-www-form-urlencoded* encoded body.
`HttpResponse::urlencoded()` method returns
[*UrlEncoded*](../actix_web/dev/struct.UrlEncoded.html) future, it resolves
into `HashMap<String, String>` which contains decoded parameters.
*UrlEncoded* future can resolve into a error in several cases:
* content type is not `application/x-www-form-urlencoded`
* transfer encoding is `chunked`.
* content-length is greater than 256k
* payload terminates with error.
```rust
# extern crate actix_web;
# extern crate futures;
use actix_web::*;
use futures::future::{Future, ok};
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
Box::new(
req.urlencoded() // <- get UrlEncoded future
.and_then(|params| { // <- url encoded parameters
println!("==== BODY ==== {:?}", params);
ok(httpcodes::HTTPOk.response())
})
.map_err(Error::from)
)
}
# fn main() {}
```
2017-12-14 07:36:28 +01:00
## Streaming request
2017-12-19 09:29:25 +01:00
Actix uses [*Payload*](../actix_web/payload/struct.Payload.html) object as request payload stream.
2017-12-19 09:18:57 +01:00
*HttpRequest* provides several methods, which can be used for payload access.
At the same time *Payload* implements *Stream* trait, so it could be used with various
stream combinators. Also *Payload* provides serveral convinience methods that return
future object that resolve to Bytes object.
* *readany* method returns *Stream* of *Bytes* objects.
* *readexactly* method returns *Future* that resolves when specified number of bytes
get received.
* *readline* method returns *Future* that resolves when `\n` get received.
* *readuntil* method returns *Future* that resolves when specified bytes string
matches in input bytes stream
2017-12-19 18:51:28 +01:00
In this example handle reads request payload chunk by chunk and prints every chunk.
2017-12-19 09:18:57 +01:00
```rust
# extern crate actix_web;
# extern crate futures;
# use futures::future::result;
use actix_web::*;
use futures::{Future, Stream};
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
Box::new(
req.payload_mut()
.readany()
.fold((), |_, chunk| {
println!("Chunk: {:?}", chunk);
result::<_, error::PayloadError>(Ok(()))
})
.map_err(|e| Error::from(e))
.map(|_| HttpResponse::Ok().finish().unwrap()))
}
# fn main() {}
```