我想实现一个惰性静态reqwest::ClientBuilder。注意,这是针对实用程序模块的,因此我有一种感觉,在这种情况下很难避免使用静态。我想构建它一次,然后用它来构建可能的几个
reqwest::Client
(对于不同的超时,这是在客户端构建时设置的)。
所以我有这一行(使用
once_cell::sync::Lazy
):
static CLIENT_BUILDER: Lazy<Mutex<Option<ClientBuilder>>> = Lazy::new(|| Mutex::new(None));
然后我有这个功能:
pub fn get_reqwest_client(timeout: u64 = 5_000) -> Result<Client, Box<dyn std::error::Error>> {
let mut client_builder_guard = CLIENT_BUILDER.lock().unwrap();
let client_builder = match client_builder_guard.as_ref() {
Some(client_builder) => client_builder,
None => {
// configuration of builder
let es_path = r#"D:\apps\ElasticSearch\elasticsearch-8.6.2\config"#;
set_var("ES_PATH_CONF", &es_path); // from crate tmp_env
let mut buf = Vec::new();
let cert_path = format!(r#"{es_path}\certs\http_ca.crt"#);
let mut cert_file = File::open(cert_path).expect("problem opening certificate file");
let _ = cert_file.read_to_end(&mut buf);
let cert = reqwest::Certificate::from_pem(&buf).expect("problem generating certificate");
let client_builder = Client::builder()
.add_root_certificate(cert);
// setting the Lazy Mutex
*client_builder_guard = Some(client_builder);
client_builder_guard.as_ref().unwrap()
}
};
...
稍后在该函数中:
let client = client_builder.as_ref()
.timeout(std::time::Duration::from_millis(timeout))
.build()?;
这会产生错误:
error[E0599]: the method `as_ref` exists for reference `&ClientBuilder`, but its trait bounds were not satisfied
--> D:\My documents\software projects\EclipseWorkspace\doc_indexer\src\core\utilities\src\lib.rs:154:35
|
154 | let client = client_builder.as_ref()
| ^^^^^^ method cannot be called on `&ClientBuilder` due to unsatisfied trait bounds
|
::: D:\apps\rust\rust_1.70.0\.cargo\registry\src\index.crates.io-6f17d22bba15001f\reqwest-0.11.20\src\blocking\client.rs:69:1
|
69 | pub struct ClientBuilder {
| ------------------------ doesn't satisfy `reqwest::blocking::ClientBuilder: AsRef<_>`
|
= note: the following trait bounds were not satisfied:
`reqwest::blocking::ClientBuilder: AsRef<_>`
which is required by `&reqwest::blocking::ClientBuilder: AsRef<_>`
我也尝试过
*client_builder
和client_builder.clone();
甚至client_builder_guard.as_ref().unwrap()
。似乎没什么作用。
为什么会涉及到
Copy
特质?有解决办法吗?我重新阅读了编译器消息,但不明白(例如,我找到了这个答案,但从表面上看它似乎不适用)。
编辑回复评论
如果我在上面省略
as_ref()
(我已经尝试过),我会得到:
error[E0507]: cannot move out of `*client_builder` which is behind a shared reference
--> D:\My documents\software projects\EclipseWorkspace\doc_indexer\src\core\utilities\src\lib.rs:153:20
|
153 | let client = client_builder
| __________________________^
154 | | .timeout(std::time::Duration::from_millis(timeout))
| |___________________________________________________________________^ move occurs because `*client_builder` has type `reqwest::blocking::ClientBuilder`, which does not implement the `Copy` trait
这个问题的答案可能对其他人有帮助,不仅适用于
reqwest::ClientBuilder
,还可能适用于其他“构建器”类型模式。
对于用户4815162342指出的问题的解释是,
ClientBuilder.build
的签名是pub fn build(self) -> Result<Client>
。因此,它消耗了构建器,这意味着每个客户端都需要一个新的构建器。尝试创建可重用构建器所引起的问题导致了难以理解的编译器消息。
...不幸的是
set_timeout
不是可用于 reqwest::Client
的可选可链接方法之一,因此我选择了静态超时到客户端映射。