尝试从actix-web路由处理程序功能内进行请求时出现错误“ BlockingClientInFutureContext”

时间:2019-08-17 22:48:59

标签: rust actix-web reqwest

我正在用Rust 2018 Stable和Actix-Web编写Web服务。使用Reqwest,我从一个路由处理程序功能内向另一个站点发出了HTTP请求。简单来说就是这样

extern crate reqwest;
use actix_web;
use reqwest::Url;

pub fn testing(req: actix_web::HttpRequest) -> actix_web::Result<actix_web::HttpResponse> {
    println!(">>> testing request begin");
    let url = Url::parse("https://example.com/").unwrap();
    println!(">>> testing url built");
    let req = reqwest::Client::new().post(url);
    println!(">>> testing req prepared");
    let res_struct = req.send();
    println!(">>> testing res_struct received");
    let res = res_struct.unwrap();
    println!(">>> testing res unwrapped");
    Ok(format!("done.").into())
}

那是行不通的,并且我收到以下错误消息(尽管仅调用了一次函数,但该错误被打印了8次,“ worker:1”至“ worker:8”):

thread 'actix-rt:worker:1' panicked at 'called `Result::unwrap()` 
on an `Err` value: Error(BlockingClientInFutureContext, 
"https://www.example.com/")', src/libcore/result.rs:999:5
Panic in Arbiter thread, shutting down system.

Google在“ BlockingClientInFutureContext” 上找不到任何有用的东西,但是我想它与async / await或Tokio自己的未来有某种联系?

感谢任何有关阅读内容的指导。另外,我是Rust的新手。

从Actix-Web HTttpServer调用处理程序函数

HttpServer::new(|| App::new().service(
    web::resource("/testing").route(
        web::get().to(views::testing)
    )
)).bind("127.0.0.1:8001")?.run()

4 个答案:

答案 0 :(得分:5)

我有一个类似的问题。对我来说,解决方法是将Reqwest板条箱版本锁定在您的货运文件中,并固定为0.9.17,然后重新构建。

reqwest = "=0.9.17"

除非您在两者上都使用了异步功能,否则看来新版本的Reqwest已被Actix-web破坏了。供参考:https://github.com/seanmonstar/reqwest/issues/541

答案 1 :(得分:3)

结果证明,actix_web::web::block()是正确的猜测。使用它可以进行阻塞呼叫。 block()返回的Future会在网络请求返回数据后解析。非常接近JS中的Promises,加上其中的.from_err()

pub fn testing(_req: actix_web::HttpRequest)
    -> impl Future<Item = HttpResponse, Error = Error>
{
    println!(">>> testing request begin");
    let url = Url::parse("https://example.com/").unwrap();
    println!(">>> testing url built");
    let req = reqwest::Client::new().get(url);
    println!(">>> testing req prepared");

    actix_web::web::block(move || {
        println!(">>> testing res received");
        req.send()
    })
    .from_err()
    .and_then(|res| {
        println!(">>> testing res: {:?}", &res);
        HttpResponse::Ok().content_type("text/html").body("Hello!")
    })
}

此外,在main.rs中,必须使用.to_async()而非简单的.to()来调用路由:

HttpServer::new(|| App::new().service(
    web::resource("/testing").route(
        web::get().to_async(views::testing)
    )
)).bind("127.0.0.1:8001")?.run()

答案 2 :(得分:1)

TL; DR:升级到reqwest 0.9.22或更高版本。

该错误表明您正在尝试从异步上下文内部进行阻止的网络调用(Actix Web处理程序被异步调用)。 reqwest 0.9.17-0.9.21版本不支持此功能。

从0.9.22开始,作者已删除此错误,并发出警告。有关更多信息:

https://github.com/seanmonstar/reqwest/pull/670

https://github.com/seanmonstar/reqwest/issues/541

答案 3 :(得分:0)

由于返回错误,因此对unwrap()的调用失败。最好避免在生产代码中使用unwrap(),因为它通常意味着我们在忽略错误路径的同时试图查看“所需”值(通常称为“快乐路径”)。

此代码有效:

use actix_web;
use reqwest::Url;

fn main()  {
    println!(">>> testing request begin");
    let url = Url::parse("http:/example.com/").unwrap();
    println!(">>> testing url built");
    let req = reqwest::Client::new().post(url);
    println!(">>> testing req prepared");
    let res_struct = req.send();
    println!(">>> testing res_struct received");
    match res_struct {
        Ok(r)=> println!("response: {:?}", r),
        Err(e)=> println!("error: {}", e),
    }
//    let res = res_struct.unwrap();
    println!("done.");
}

输出为:

Finished dev [unoptimized + debuginfo] target(s) in 2.63s
     Running `target/debug/untitled`
>>> testing request begin
>>> testing url built
>>> testing req prepared
>>> testing res_struct received
error: http://example.com/: error trying to connect: failed to lookup address information: nodename nor servname provided, or not known
>>> testing res unwrapped
done.

上面的代码可以正常工作,但是example.com上的服务器没有提供良好的响应。 如果我使用有效的网址重新运行此代码,例如https://cisco.com,我没有任何错误:

>>> testing request begin
>>> testing url built
>>> testing req prepared
>>> testing res_struct received
response: Response { url: "https://www.cisco.com/", status: 200, headers: {"server": "Apache", "etag": "\"1732e-59058880c8465\"", "accept-ranges": "bytes", "strict-transport-security": "max-age=31536000", "cdchost": "wemxweb-publish-prod2-02", "x-xss-protection": "1; mode=block", "x-test-debug": "nURL=www.cisco.com,realm=0,isRealm=0,realmDomain=0,shortrealm=0", "content-security-policy": "upgrade-insecure-requests; frame-ancestors *.cisco.com *.jasper.com *.ciscospark.com *.ciscolive.com  http://cisco.lookbookhq.com https://cisco.lookbookhq.com testcisco.marketing.adobe.com cisco.marketing.adobe.com ciscosales.my.salesforce.com test.salesforce.com zedo.com hindustantimes.com economictimes.indiatimes.com *.webex.com *.cdw.com *.cdwg.com *.cdw.ca *.meraki-go.com http://ciscopartners.lookbookhq.com https://ciscopartners.lookbookhq.com ciscolearningsystem.com ciscocustomer.lookbookhq.com cisco.lookbookhq.com;", "content-type": "text/html", "expires": "Sun, 18 Aug 2019 12:10:23 GMT", "cache-control": "max-age=0, no-cache, no-store", "pragma": "no-cache", "date": "Sun, 18 Aug 2019 12:10:23 GMT", "connection": "keep-alive", "vary": "Accept-Encoding"} }
>>> testing res unwrapped
done.