1# ylong_http 用户指南
2
3ylong_http 提供了 HTTP 各个版本下的协议所需的各种基础组件和扩展组件,方便用户组织所需的 HTTP 结构。
4
5ylong_http 整体分为 2 个库:
6
7- ylong_http_client 库:HTTP 客户端库
8- ylong_http 库:HTTP 协议及组件库
9
10其中 ylong_http_client 库提供了 HTTP 客户端的功能,ylong_http 库提供了 HTTP 协议的基础组件。
11
12如果需要查看详细的接口说明请查看对应接口的 docs,可以使用 `cargo doc --open` 生成并查看 docs。
13
14## ylong_http_client
15
16用户可以使用 ylong_http_client 库来创建自定义的客户端。
17
18用户可以使用自定义客户端来向指定服务端发送请求,然后接收响应。
19
20在使用 ylong_http_client 的功能之前,请保证在 `BUILD.gn` 或 `Cargo.toml` 中已成功添加依赖并开启对应 feature。
21
22当前支持的功能:
23
24- 支持异步 HTTP 客户端创建
25- 支持 HTTP/1.1
26- 支持 HTTPS
27- 支持上传下载回调
28- 支持简单的 Mime 格式传输
29
30#### 创建一个异步客户端
31
32用户可以使用 `ylong_http_client::async_impl::Client` 来生成一个异步 HTTP 客户端。该功能被 feature `async` 控制。
33
34用户可以使用 `Client::new()` 直接生成默认配置的客户端:
35
36```rust
37use ylong_http_client::async_impl::Client;
38
39async fn create_default_client() {
40    // 创建一个默认配置选项的客户端。
41    let _client_default = Client::new();
42}
43```
44
45用户也可以使用 `Client::builder()` 自定义客户端:
46
47```rust
48use ylong_http_client::async_impl::Client;
49use ylong_http_client::Timeout;
50
51async fn create_client_with_builder() {
52    let _client_with_builder = Client::builder()    // 创建 builder。
53        .connect_timeout(Timeout::from_secs(3))     // 设置一些自定义选项。
54        .request_timeout(Timeout::from_secs(3))
55        .build();                                   // 构建 Client。
56}
57```
58
59当前版本提供的 Client 的配置选项:
60
61- `connect_timeout`: 设置连接超时时间
62- `request_timeout`: 设置请求超时时间
63- `redirect`: 设置重定向逻辑
64- `proxy`: 设置代理逻辑
65- `tls_built_in_root_certs`: 是否使用预置证书
66- `add_root_certificate`: 设置根证书
67- `min_tls_version`: 设置 TLS 版本下限
68- `max_tls_version`: 设置 TLS 版本上限
69- `set_cipher_suite`: 设置 TLSv1.3 的算法套件
70- `set_cipher_list`: 设置 TLSv1.3 之前版本的算法套件
71- `set_ca_file`: 设置 CA 证书文件路径
72
73#### 创建请求
74
75用户可以使用 `Request` 结构提供的快速接口来生成 HTTP 请求。
76
77```rust
78use ylong_http_client::Request;
79
80async fn create_default_request() {
81    // 创建一个为 url 为 127.0.0.1:3000,body 为空的 GET 请求。
82    let _request_default = Request::get("127.0.0.1:3000").body("".as_bytes()).unwrap();
83}
84```
85
86用户也可以利用 `Request::builder()` 来自定义请求。
87
88```rust
89use ylong_http_client::{Request, Method};
90
91async fn create_request_with_builder() {
92    let _request_with_builder = Request::builder()  // 创建 RequestBuilder
93        .method(Method::GET)    // 设置 Method
94        .url("http://www.example.com")  // 设置 Url
95        .header("Content-Type", "application/octet-stream") // 设置 Header
96        .body("".as_bytes());   // 设置 body
97}
98```
99
100当前版本提供的 Request 的配置选项:
101
102- `method`: 设置请求方法
103- `url`: 设置 Url
104- `header`: 插入请求头字段
105- `append_header`: 追加请求头字段
106- `body`: 设置一般 body 内容
107- `multipart`: 设置 multipart 格式 body 内容
108
109用户可以创建 Multipart 格式的请求:
110
111```rust
112use ylong_http_client::async_impl::{Multipart, Part};
113use ylong_http_client::Request;
114
115async fn create_multipart() {
116    // 创建单个 part
117    let part = Part::new()
118        .mime("application/octet-stream")
119        .name("name")
120        .file_name("file_name")
121        .length(Some(10))
122        .body("HelloWorld");
123
124    // 创建 Multipart。
125    let multipart = MultiPart::new().part(part);
126
127    // 使用 multipart 接口创建 Request。
128    let _request = Request::get("127.0.0.1:3000").multipart(multipart);
129}
130```
131
132用户可以在 body 的基础上,使用 `Uploader` 对上传逻辑进行控制:
133
134```rust
135use ylong_http_client::async_impl::Uploader;
136use ylong_http_client::Response;
137
138async fn create_uploader() {
139    // 创建输出到控制台的 Uploader。
140    let _uploader = Uploader::console("HelloWorld".as_bytes());
141}
142```
143
144```rust
145use std::pin::Pin;
146use std::task::{Context, Poll};
147use ylong_http_client::async_impl::{Uploader, UploadOperator};
148use ylong_http_client::HttpClientError;
149
150async fn upload_and_show_progress() {
151    // 自定义的 `UploadOperator`.
152    struct MyUploadOperator;
153
154    impl UploadOperator for MyUploadOperator {
155        fn poll_progress(
156            self: Pin<&mut Self>,
157            cx: &mut Context<'_>,
158            uploaded: u64,
159            total: Option<u64>
160        ) -> Poll<Result<(), HttpClientError>> {
161            todo!()
162        }
163    }
164
165    // 根据自定义的 Operator 创建 Uploader。
166    let uploader = Uploader::builder().reader("HelloWorld".as_bytes()).operator(MyUploadOperator).build();
167}
168```
169
170#### 发送请求、等待响应
171
172创建好 `Client` 和 `Request` 后即可利用 `Client::request` 接口发送请求并等待响应。
173
174```rust
175use ylong_http_client::async_impl::Client;
176use ylong_http_client::Request;
177
178async fn send_request<T>(client: Client, request: Request<T>) {
179    // 发送请求,等待响应。
180    let _response = client.request(request).await.unwrap();
181}
182```
183
184得到的响应会以 `Response` 结构的形式返回。响应的头字段会被完整地解析在 `Response` 结构体中,
185但是 body 部分需要用户根据自身需求在后续逻辑中读取。
186
187#### 读取响应 body
188
189得到 `Response` 后,可以对响应的 body 信息读取。
190
191用户可以通过调用 `Response::body_mut()`,获取到 body,再使用 `Body::data()` 自行读取 body 内容。
192
193```rust
194use ylong_http_client::async_impl::Body;
195use ylong_http_client::{Response, HttpClientError};
196
197async fn receive_response_body(mut response: Response) -> Result<(), HttpClientError> {
198    let mut buf = [0u8; 1024];
199    loop {
200        let size = response.body_mut().data(&mut buf).await?;
201        if size == 0 {
202            return Ok(())
203        }
204        let data = &buf[..size];
205        // 处理接收到的 data 信息。
206    }
207}
208```
209
210使用 `Downloader` 可以进行一个更加灵活的下载方式。
211
212`Downloader` 提供一个直接将 body 输出到控制台的简单方式:
213
214```rust
215use ylong_http_client::async_impl::{Downloader, HttpBody, Response};
216
217async fn download_and_show_progress_on_console(response: Response) {
218    // 将 Response body 打印到控制台,以字节方式打印。
219    let _ = Downloader::console(response).download().await;
220}
221```
222
223用户也可以自定义 `Downloader` 中的 `DownloadOperator` 组件来实现灵活的自定义下载操作。
224
225用户需要给自身结构体实现 `DownloadOperator` trait,实现其中的 `poll_download` 和
226`poll_progress` 方法,以实现下载和显示回调功能。
227
228```rust
229use std::pin::Pin;
230use std::task::{Context, Poll};
231use ylong_http_client::async_impl::{Downloader, DownloadOperatorResponse};
232use ylong_http_client::{HttpClientError, SpeedLimit, Timeout};
233
234async fn download_and_show_progress(response: Response) {
235    // 自定义的 `DownloadOperator`.
236    struct MyDownloadOperator;
237
238    // 为自定义结构实现 DownloadOperator。
239    impl DownloadOperator for MyDownloadOperator {
240         fn poll_download(
241             self: Pin<&mut Self>,
242             cx: &mut Context<'_>,
243             data: &[u8],
244         ) -> Poll<Result<usize, HttpClientError>> {
245             // 自定义 download 函数,每次从 Response 中读取到 data 后都会自动调用该接口。
246             todo!()
247         }
248
249         fn poll_progress(
250             self: Pin<&mut Self>,
251             cx: &mut Context<'_>,
252             downloaded: u64,
253             total: Option<u64>
254         ) -> Poll<Result<(), HttpClientError>> {
255             // 自定义 progress 函数,每次从 Response 中读取到 data 并处理后会调用该接口进行显示回调。
256             todo!()
257         }
258     }
259
260     // 创建 Downloader 对指定 Response 进行下载。
261     let mut downloader = Downloader::builder()
262         .body(response)    // 设置 response
263         .operator(MyDownloadOperator)  // 设置 operator
264         .build();
265     let _ = downloader.download().await;
266}
267```