我希望通过添加在响应为 401 时捕获、重新验证和重试的逻辑来改进一些为
reqwest::Response
制作和返回 Future 的逻辑。但是,即使在我开始重试逻辑之前,我的尝试将 reqwest::Response
的创建移至异步方法(将在其中放置重新验证逻辑)会因生命周期错误而失败。
要替换的原始工作代码是结构体中的非异步方法,返回装箱的 future;
self.Client
是一个 reqwest::Client
并且该项目正在使用 tokio 运行时:
pub fn demo_good(
&mut self,
url: Url,
) -> Pin<Box<dyn futures::Future<Output = Result<Response, Error>> + Send>> {
let mut map = HashMap::new();
map.insert("fake_key".to_string(), "fake_value".to_string());
let response = self.client.post(url).json(&map).send();
Box::pin(response)
}
但是,一旦我尝试开始将
self.client.post(...)...
逻辑移动到结构的异步方法中,我就会收到生命周期错误:
// POST to the execute_url, handling reauthentication
async fn demo_post(
&mut self,
url: Url,
body: HashMap<String, String>,
) -> Result<Response, Error> {
// Run first request
let response = self.client.post(url).json(&body).send().await;
// Todo: catch 401s, reauth, and repeat
dbg!(&response);
// Return
response
}
pub fn demo_bad(
&mut self,
url: Url,
) -> Pin<Box<dyn futures::Future<Output = Result<Response, Error>> + Send>> {
let mut map = HashMap::new();
map.insert("fake_key".to_string(), "fake_value".to_string());
let response = self.demo_post(url, map);
Box::pin(response)
}
Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
--> src/lib.rs:41:9
|
35 | &mut self,
| - let's call the lifetime of this reference `'1`
...
41 | Box::pin(response)
| ^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
|
help: to declare that the trait object captures data from argument `self`, you can add an explicit `'_` lifetime bound
|
37 | ) -> Pin<Box<dyn futures::Future<Output = Result<Response, Error>> + Send + '_>> {
|
我可以遵循这里的建议,但这并没有“实际上”从参数 self
中捕获比原始工作
demo_good
方法更多的数据。此外,我实际上确实想返回这个未来的响应以在代码库的其他地方使用,并且我担心新的生命周期约束只会进一步解决问题,导致像error[E0515]: cannot return value referencing temporary value
这样的错误,这是我以前没有的。是否有其他方法可以使这样的策略发挥作用,也许可以通过在某些方法签名中指定生命周期参数?或者它注定会失败,因为原始的 reqwest 方法(非异步并返回 Futures)和我添加的包装器方法(异步)之间的差异,并且有一些不同的设计可供使用?
这里是 Rust 游乐场中此代码的链接:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5e92c7a6977c2a4cdaa51dae7419c266impl Trait
而不是
async fn
来说服编译器:// POST to the execute_url, handling reauthentication
fn demo_post(
&mut self,
url: Url,
body: HashMap<String, String>,
) -> impl Future<Output = Result<Response, Error>> {
let request = self.client.post(url);
async move {
// Run first request
let response = request.json(&body).send().await;
// Todo: catch 401s, reauth, and repeat
dbg!(&response);
// Return
response
}
}