2016-04-03 1 views
1

Я пытаюсь использовать инфраструктуру Iron для создания простого бэкэнда в Rust. Этот обработчик должен только возвращать содержимое определенного файла, и я могу заставить его работать правильно с unwrap(), но я хочу попытаться выполнить правильную обработку ошибок. Это, как я предположил бы, что это будет выглядеть так:Если результат возвращает Err (_), я хочу, чтобы вся функция возвращала ошибку HTTP-запроса.

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 и железного Err? Хотя я не уверен. И в прошлом я не делал много веб-разработки (или Rust), так что любая обратная связь с кодом также ценится!

ОБНОВЛЕНИЕ: Я думаю, что это более «путь ржавчины» для этого? Но я не уверен,

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 также необходимо позаботиться и что бы создать вложенную беспорядок обработки ошибок? Однако эти совпадающие руки, очевидно, несовместимы, поэтому они не сработают ... никаких предложений?

ответ

2

занимает Response, но Err() занимает IronError.

Следовательно, ваш звонок Err(...) недействителен, если ... - это номер Response!

Как исправить? Ну, первый шаг, вы должны создать IronError для отправки назад. Я считаю (не знакомы с 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 с std::IoError, что вы вернулись из File::open():

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: обработка ошибок»! Как красиво!

(код тестировался, пожалуйста, отредактировать, если компиляция завершится неудачно)

+0

ли идиоматически правильно сделать остальную часть кода части внутренней обработки ошибок? Учитывая, что мне нужно обработать результат '' 'read_to_string''', не создаст ли он вложенный беспорядок обработки ошибок? – mnordber

+0

Возможно, было бы идиоматическим, чтобы сначала увидеть, применим ли макрос 'try!' (Я не знаю, относится ли это к типам ошибок Iron и/или подписи вашей функции.) Если это не так, хорошее обходное решение будет состоять в следующем: 'let what_you_want = match ... {...}' и 1. сделайте конец ветки Ok с what_you_want 2. ранним возвратом из ветви Err. Таким образом, вы можете продолжить работу без гнезда. Собственно, это философия, стоящая за «try!». – mdup

+0

Да, я пытался использовать 'try!'сначала, но было какое-то столкновение с пакетом Iron. Является ли решение просто отказаться от «try!» Или вы можете обойти это? Я также попробовал подход 'let what_you_want = match', но оказался в беспорядке с оружием, не имеющим соответствующих типов. Что такое раннее возвращение? Это просто добавление возврата? 'return Err (HttpError :: Io (err))'? Потому что проблема, которую я получаю, заключается в том, что я возвращаю «гипер :: ошибка: ошибка», но она выдает «iron :: error :: IronError» ... – mnordber

Смежные вопросы