Rust reqwest CookieStore 与 Session

发布网友

我来回答

1个回答

热心网友

reqwest 默认不提供 cookies 功能,导致连续多次发送请求时,上一次的响应 cookie 无法保存,也不会自动带上。若需启用 cookies 功能,需要开启 cookies feature,并使用 ClientBuilder::cookie_store() 或 ClientBuilder::cookie_provider() 方法进行配置。

在 reqwest::cookie module 中,定义了 CookieStore trait。reqwest 在 cookie module 中还提供了一个 CookieStore 实现——Jar。Jar 将 cookie 保存在内存中,不具备持久化功能。其实现如下:

Jar 完全依赖于 cookie_store::CookieStore 实现,而 cookie_store 是一个单独的 crate,实现了 RFC6265 规定的 cookie 功能。

reqwest::cookie::CookieStore 是一个 trait,而 cookie_store::CookieStore 是一个 struct。cookie_store::CookieStore 提供了持久化相关功能,如 load/load_all/load_json/load_json_all/save/save_json 等 method,但 Jar 没有暴露这些功能。

另一个 crate reqwest_cookie_store 提供了两个 reqwest::cookie::CookieStore 实现——CookieStoreMutex 和 CookieStoreRwLock,方便与 reqwest 集成。它们也基于 cookie_store::CookieStore 实现,并提供了方法暴露所依赖的 cookie_store::CookieStore 实现,因此具有持久化功能。CookieStoreMutex 和 CookieStoreRwLock 在 cookie_store::CookieStore 外面套了一把锁,通过 lock()/read()/write() 等方法即可访问里面的 cookie_store::CookieStore。因此,它们也具有持久化功能。

总结一下,reqwest 默认没有开启 cookies 支持,需要手动开启。reqwest 提供了 Jar 作为 reqwest::cookie::CookieStore 实现,但它不支持持久化功能。reqwest_cookie_store::CookieStoreMutex 和 reqwest_cookie_store::CookieStoreRwLock 实现了 reqwest::cookie::CookieStore,并支持持久化。这三个实现都是基于 cookie_store::CookieStore 的。

Session = Client + cookie store

Cookies 是 HTTP 协议的重要补充,使得多次请求/响应形成一个会话(Session)。下面探讨如何实现 Session。

以知乎命令行工具为例,我们需要实现一个场景:需求是写一个知乎命令行工具,但知乎的很多功能需要登录后才能使用,如点赞、评论、私信等。期望登录后,知乎的 cookies 保存在本地文件中,启动时从本地文件加载 cookies。使用过程中,cookies 可能会过期或更新,因此退出时也需要将最新的 cookies 信息保存下来,以保证登录一次后,在有效期内不必反复登录,提升使用体验。

结合 reqwest 的 cookies 相关 API,我们需要一个基于本地文件的 CookieStore 实现。为了让 Session 更易用,我们需要让 Session 的 API 尽量与 Client 的 API 接近。

考虑到这些要求,我们可以实现如下:Session 包装了 Client 和 State。HTTP 请求由 Client 处理,而 cookies 的自动加载/存储由 State 处理。Session 实现了 Deref,可以当作 Client 一样使用。

Session 的实现还考虑了并发使用场景。Session 持有的是 State 的 Arc 指针和 Client 实例,而 Client 的主要部分也是一个 Arc 指针,因此 Session 的 clone 成本很低。若需要在多个线程中并发使用 Session,直接 clone 出多个实例即可。使用完毕,只有当 Session 的所有实例都 drop 之后,才会触发 State 的 drop 操作,并自动将 cookies 保存到本地文件。

当然,这个实现也有其缺点。reqwest 的 Client 由 ClientBuilder 提供了丰富的构建 API,但 Session 缺少这些选择。如果确实有需求,我们也可以提供一个 SessionBuilder 来封装 ClientBuilder 的功能。

另外,reqwest 既支持 blocking client 也支持 nonblocking client。这个示例只实现了 blocking client 的 session。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com