【问题标题】:If a Result returns Err(_), I want the whole function to return a HTTP request error如果一个结果返回 Err(_),我希望整个函数返回一个 HTTP 请求错误
【发布时间】:2016-07-22 21:15:14
【问题描述】:

我正在尝试使用 Iron 框架在 Rust 中构建一个简单的后端。这个处理程序只是应该返回某个文件的内容,我可以让它与unwrap() 一起正常工作,但我想尝试做正确的错误处理。这就是我想象的样子:

fn get_content(res: &mut Request) -> IronResult<Response> {
    let mut id = String::new();
    res.body.read_to_string(&mut id).unwrap();

    let file_path_string = &("../content/".to_string() + &id + ".rdt");

    // TODO: Error handling
    match File::open(file_path_string) {
        Ok(f) => {
            let mut s = String::new();
            f.read_to_string(&mut s);
            Ok(Response::with(((status::Ok), s)))
        }
        Err(err) => Err(Response::with(((status::InternalServerError), "File not found")))
    };
}

这会引发错误not all control paths return a value [E0269],这很好。但是如果我在匹配部分之后添加响应:

match File::open(file_path_string) {
    Ok(f) => {
        let mut s = String::new();
        f.read_to_string(&mut s);
        Ok(Response::with(((status::Ok), s)))
    }
    Err(err) => Err(Response::with(((status::InternalServerError), "File not found")))
};

Err(Response::with(((status::InternalServerError), "File not found")))

我反而收到错误消息:

expected `iron::error::IronError`,
    found `iron::response::Response`
(expected struct `iron::error::IronError`,
    found struct `iron::response::Response`) [E0308]
src/main.rs:95        
Err(Response::with(((status::InternalServerError), "File not found")))

我认为问题在于 Rust Err 和 Iron Err 之间的冲突?不过我不确定。而且我过去没有做过太多的 Web 开发(或 Rust),所以对代码的任何反馈也很感激!

更新:我认为这更像是“Rust Way”吗?但我不确定

fn get_content(res: &mut Request) -> IronResult<Response> {
    let mut id = String::new();
    res.body.read_to_string(&mut id).unwrap();

    let file_path_string = &("../content/".to_string() + &id + ".rdt");

    // TODO: Error handling
    let f;
    match File::open(file_path_string) {
        Ok(file) => f = file,
        Err(err) => Err(HttpError::Io(err))
    };
    let mut s = String::new();
    f.read_to_string(&mut s);
    Ok(Response::with(((status::Ok), s)))
}

在错误处理中包含代码似乎很奇怪,因为read_to_string 也需要注意,这会造成错误处理的嵌套混乱?然而,这些匹配的手臂显然是不兼容的类型,所以它不会工作......有什么建议吗?

【问题讨论】:

    标签: rust iron


    【解决方案1】:

    Ok() 采用 Response,但 Err() 采用 IronError

    因此,当...Response 时,您的呼叫Err(...) 无效!

    如何纠正?第一步是,您必须创建一个IronError 才能发回。我相信(不熟悉 Iron)Iron 会自动生成适当的错误代码,而这不是你的工作。在文档中,我们找到了一种实现 IronError 的键类型:

    pub enum HttpError {
        Method,
        Uri(ParseError),
        Version,
        Header,
        TooLarge,
        Status,
        Io(Error),
        Ssl(Box<Error + 'static + Send + Sync>),
        Http2(HttpError),
        Utf8(Utf8Error),
        // some variants omitted
    }
    

    我看不到一个允许像“找不到文件”这样的任意字符串的字符串。但是,您的用例是 IO 故障之一,对吧?因此,将HttpError::Io 与您从File::open() 返回的std::IoError 一起使用是有意义的:

    match File::open(file_path_string) {
        Ok(f) => {
            let mut s = String::new();
            f.read_to_string(&mut s);
            Ok(Response::with(((status::Ok), s)))
        }
        Err(err) => Err(HttpError::Io(err))
    };
    

    顺便说一句,它还修复了您的“TODO:错误处理”!多么美丽!

    (代码未经测试,如果编译失败请随时编辑)

    【讨论】:

    • 在错误处理中执行其余代码部分在惯用上是否正确?考虑到我需要处理read_to_string 的结果,会不会造成嵌套的错误处理混乱?
    • 我想,惯用的方法是首先查看 try! 宏是否适用(我不知道它是否与 Iron 的错误类型和/或您的函数的签名有关。)如果不是,一个好的解决方法是如下构造:let what_you_want = match ... { ... } 和 1. 使 Ok 分支以 what_you_want 结束 2. 从 Err 分支提前返回。这样你就可以在下面继续而不嵌套。其实这就是try!背后的理念。
    • 是的,我一开始尝试使用try!,但与 Iron 包发生了某种冲突。解决方案是简单地放弃try! 还是可以解决这个问题?我也尝试了let what_you_want = match 方法,但结果是一堆没有匹配类型的武器。什么是提前退货?只是简单地添加回报吗? return Err(HttpError::Io(err))?因为我遇到的问题是我返回一个hyper::error:Error,但它正在加速iron::error::IronError...
    • “提前退货”,是的,我的意思是简单地添加退货,正如您所描述的。至于您的后一个问题,我看了一下 Iron 示例;我不确定,我现在没有设置来测试它,但也许可以试试return IronError::new(HttpError::Io(err), status::InternalServerError)
    • 谢谢!我让它工作了!我不得不在你的建议周围添加Err(...),但现在它可以工作了!
    猜你喜欢
    • 2021-01-25
    • 2020-04-25
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 2022-07-10
    • 1970-01-01
    相关资源
    最近更新 更多