如何在中间件和处理程序中读取Iron请求?

时间:2016-04-05 19:28:04

标签: request rust middleware iron

我正在研究Rust中的一个小API,但我不确定如何在两个地方从Iron访问Request

Authentication中间件为令牌读取Request一次,如果允许路径(当前没有检查),实际路由会再次尝试读取它。这给了我一个EOF错误,因为已经读取了请求。

我似乎无法轻易克隆请求,我相信它必须是可变的才能阅读正文。

extern crate iron;
extern crate router;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::{BeforeMiddleware, status};
use router::Router;
use rustc_serialize::json;
use rustc_serialize::json::Json;
use std::io::Read;

#[derive(RustcEncodable, RustcDecodable)]
struct Greeting {
    msg: String
}

struct Authentication;

fn main() {
    let mut request_body = String::new();

    impl BeforeMiddleware for Authentication {
        fn before(&self, request: &mut Request) -> IronResult<()> {
            let mut payload = String::new();
            request.body.read_to_string(&mut payload).unwrap();
            let json = Json::from_str(&payload).unwrap();

            println!("json: {}", json);

            let token = json.as_object()
                .and_then(|obj| obj.get("token"))
                .and_then(|token| token.as_string())
                .unwrap_or_else(|| {
                    panic!("Unable to get token");
                });

            println!("token: {}", token);

            Ok(())
        }
    }

    fn attr(input: String, attribute: &str) -> String {
        let json = Json::from_str(&input).unwrap();
        let output = json.as_object()
            .and_then(|obj| obj.get(attribute))
            .and_then(|a| a.as_string())
            .unwrap_or_else(|| {
                panic!("Unable to get attribute {}", attribute);
            });

        String::from(output)
    }

    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let greeting = Greeting { msg: "Hello, world!".to_string() };
        let payload = json::encode(&greeting).unwrap();
        Ok(Response::with((status::Ok, payload)))
    }

    // Receive a message by POST and play it back if auth-key is correct.
    fn set_greeting(request: &mut Request) -> IronResult<Response> {
        let mut payload = String::new();
        request.body.read_to_string(&mut payload).unwrap();
        let json = Json::from_str(&payload).unwrap();

        println!("json: {}", json);

        let msg = attr(payload, "msg");

        println!("msg: {}", msg);

        let greeting = Greeting { msg: String::from(msg) };
        let payload = json::encode(&greeting).unwrap();

        Ok(Response::with((status::Ok, payload)))
    }

    let mut router = Router::new();

    router.get("/", hello_world);
    router.post("/set", set_greeting);

    let mut chain = Chain::new(router);
    chain.link_before(Authentication);

    Iron::new(chain).http("localhost:3000").unwrap();
}

1 个答案:

答案 0 :(得分:5)

如果不确定,我不认为你可以做任何重新阅读身体的事情(出于性能原因,你可能不想这样做)。相反,您可以让中间件解析数据,然后将其存储在Request.extensions中。然后你的路线会把它读出来:

struct AuthenticatedBody;

impl iron::typemap::Key for AuthenticatedBody {
    type Value = Json;
}

struct Authentication;

impl BeforeMiddleware for Authentication {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        let mut payload = String::new();
        request.body.read_to_string(&mut payload).unwrap();
        let json = Json::from_str(&payload).unwrap();

        {
            let token = json.as_object()
                .and_then(|obj| obj.get("token"))
                .and_then(|token| token.as_string())
                .unwrap_or_else(|| panic!("Unable to get token"));
        } // Scoped to end the borrow of `json`

        request.extensions.insert::<AuthenticatedBody>(json);

        Ok(())
    }
}

// ...

fn set_greeting(request: &mut Request) -> IronResult<Response> {
    let json = request.extensions.get::<AuthenticatedBody>().unwrap();
    // ...
}