如何在中间件和处理程序中读取Iron请求? [英] How do I read an Iron Request in both middleware and the handler?

查看:85
本文介绍了如何在中间件和处理程序中读取Iron请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Rust中使用一个小型API,并且不确定如何在两个地方从Iron中访问Request.

I'm working on a small API in Rust and am not sure how to access a Request from Iron in two places.

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

The Authentication middleware reads the Request once for a token and the actual route tries to read it again if the path is allowed (currently there is no check). This gives me an EOF error as the request has already been read.

我似乎无法轻松地克隆请求,并且我认为它必须是可变的才能读取正文.

I can't seem to easily clone the request and I believe it must be mutable in order to read the body.

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();
}

推荐答案

在不确定的情况下,我认为您无法做任何事情来重新读取车身(出于性能原因,您可能不想这样做) .相反,您可以让中间件解析数据,然后将其存储在 Request.extensions .然后您的路线将其读回:

Without knowing for sure, I don't think you can do anything to re-read the body (and you probably wouldn't want to for performance reasons). Instead, you could make your middleware parse the data and then store it in Request.extensions. Then your route would read it back out:

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();
    // ...
}

这篇关于如何在中间件和处理程序中读取Iron请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆