Как бороться с коробочной и цепной ошибкой на ржавчину? - PullRequest
3 голосов
/ 08 апреля 2020

У меня много прокси-серверов uri (http и socks5), и я использую reqwest для отправки некоторых http-запросов через прокси-серверы, и я хочу оставить прокси, если он не работает.

for proxy in proxies {
    let proxy = match Proxy::all(proxy_url) {
        Ok(proxy) => proxy,
        Err(e) => {
            eprintln!("creating proxy failed! {:?}", e);
            continue;
        }
    };

    let client = match Client::builder()
    .proxy(proxy)
    .build()

    let client = match client {
        Ok(client) => client,
        Err(e) => {
            eprintln!("building client failed! {:?}", e);
            continue;
        }
    }

    loop {
        match client.get(&config.endpoint).send().await {
            Ok(_) => {}
            Err(e) => {
                if e.is_proxy_error() { // this method doesn't exist
                    eprintln!("Dropping proxy...");
                    break;
                } else {
                    eprintln!("client error! {:?}", e);
                }
            }
        }
    }
}

И у меня есть много видов Reqwest::Error

reqwest::Error { kind: Request, url: "http://example.com/", source: hyper::Error(Connect, "socks connect error: Invalid response version") }
reqwest::Error { kind: Request, url: "http://example.com/", source: hyper::Error(Connect, "socks connect error: Proxy server unreachable") }
reqwest::Error { kind: Request, url: "http://example.com/", source: hyper::Error(Connect, "socks connect error: Connection refused") }
reqwest::Error { kind: Request, url: "http://example.com/", source: hyper::Error(Connect, "socks connect error: Connection reset by peer (os error 104)") }

В большинстве случаев сообщение об ошибке является явным, но как я могу обработать каждый из них по-разному? Поле reqwest::Error имеет inner, которое является приватным, поэтому я не могу получить к нему доступ. И если я получу источник reqwest::Error, у меня просто будет Box<syn Error>, который я не могу трактовать как hyper::Error

1 Ответ

1 голос
/ 08 апреля 2020

Вы можете уменьшить результат Error::source() до конкретного типа ошибки, например,

use std::error::Error;

...

    Err(reqwest_error) => {
        let hyper_error: Option<&hyper::Error> = reqwest_error
            .source()
            .unwrap()
            .downcast_ref();
        ...
    }

. Этот код использует unwrap() для извлечения ошибки из Option, возвращаемого source(). Если вы не можете гарантировать, что ошибка всегда будет иметь источник, вы должны использовать какой-то условный способ, чтобы развернуть источник, например

let hyper_error: Option<&hyper::Error> = reqwest_error
    .source()
    .and_then(|e| e.downcast_ref());
...