Промежуточное ПО actix_web ErrorHandlers возвращает сообщение об ошибке в ServiceResponse

Я пытаюсь зафиксировать ошибки, которые могут возникнуть при запросах к моему серверу.

Это возникло, когда я получал 400 на один из моих запросов POST (который был брошен еще до того, как я добрался до моего метода обработчика запросов), и я не получал обратной связи о том, в чем проблема, после включения журналов отладки. Я увидел проблему.

[actix_web::types::json] Failed to deserialize Json from payload. Request path: /new_endpoint
Json deserialize error: invalid length: expected one of [36, 32], found 10 at line 2 column 20
[DEBUG actix_web::middleware::logger] Error in response: Deserialize(Error("invalid length: expected one of [36, 32], found 10", line: 2, column: 20))

Теперь я хочу иметь возможность зафиксировать эту ошибку, чтобы ее можно было отправить обратно в теле ответа 400.

Я начал с

App::new()
    .wrap(ErrorHandlers::new().handler(http::StatusCode::BAD_REQUEST, handle_bad_request))

и в handle_bad_request я могу изменить тело ответа, чтобы оно содержало новую информацию

fn handle_bad_request<B>(mut res: dev::ServiceResponse<B>) -> Result<ErrorHandlerResponse<Body>> {
    res.response_mut().headers_mut().insert(
        http::header::CONTENT_TYPE,
        http::HeaderValue::from_static("application/json"),
    );
    let new_res: ServiceResponse<Body> = res.map_body(|_head, _body| {
        ResponseBody::Other(Body::Message(Box::new("New Response Body")))
    });
    Ok(ErrorHandlerResponse::Response(new_res))
}

В идеале я хочу взять ошибку в ServiceResponse и отправить ее обратно в ответ. Я могу прочитать ошибку, выполнив

match res.response().error() {
    Some(e) =>  println!("{0}", e),
    None =>  println!("Error None")
};

но что касается фактического принятия этой ошибки и отправки ее обратно в ответ, я не могу этого понять.


person rpascal    schedule 26.02.2020    source источник
comment
Разве вы не можете просто вставить format!("{:?}", res.reponse().error()) в тело ответа?   -  person Jmb    schedule 26.02.2020
comment
Только что получил шанс попробовать это, и, похоже, он работает! Не могу поверить, что никогда не думал попробовать это. Я обновлю ответ здесь в ближайшее время.   -  person rpascal    schedule 27.02.2020


Ответы (1)


Для решения этого потребовалось format!("{:?}", res.reponse().error()). Это возвращает Some(error message), так что просто чтобы учесть это, сработало следующее.

let errorMsg: String = match res.response().error() {
    Some(e) => format!("{:?}", e),
    None =>  String::from("Unknown Error")
};
let new_res: ServiceResponse<Body> = res.map_body(|_head, _body| {
    ResponseBody::Other(Body::Message(Box::new(errorMsg)))
});
Ok(ErrorHandlerResponse::Response(new_res))
person rpascal    schedule 27.02.2020