reqrio 0.3.0-alpha2

A lightweight, high-performance, fingerprint-based HTTP request library.
Documentation
# ๐Ÿ“ฆ reqrio - ไธ€ไธช่ฝป้‡ใ€้ซ˜ๆ€ง่ƒฝใ€ๆŒ‡็บน็บง็š„HTTP ่ฏทๆฑ‚ๅบ“


      `reqrio` ๆ˜ฏไธ€ไธช้ขๅ‘้ซ˜ๆ€ง่ƒฝไธŽๆต่งˆๅ™จ็บง่กŒไธบๆจกๆ‹Ÿ่ฎพ่ฎก็š„HTTP่ฏทๆฑ‚ๅบ“๏ผŒไธป่ฆ็”จไบŽ้œ€่ฆ็ฒพ็กฎๆŽงๅˆถ็ฝ‘็ปœ่กŒไธบ็š„ๅœบๆ™ฏ๏ผŒ
ๆฏ”ๅฆ‚ๅ่ฎฎ็ ”็ฉถใ€ๆŒ‡็บนๅˆ†ๆžใ€้ซ˜ๅนถๅ‘้‡‡้›†ไปฅๅŠๅคๆ‚ๅ็ˆฌ็Žฏๅขƒไธ‹็š„่ฏทๆฑ‚ๆž„้€ ใ€‚ ๅฎƒๅนถไธๆ˜ฏไผ ็ปŸๆ„ไน‰ไธŠ่ฟฝๆฑ‚โ€œ็ฎ€ๅ•ๆ˜“็”จโ€็š„HTTPๅฎขๆˆท็ซฏ๏ผŒ่€Œๆ˜ฏๆ›ดๅๅ‘ๅบ•ๅฑ‚่ฏทๆฑ‚่กŒไธบ็š„ๅฏๆŽง
ๆ€งไธŽไธ€่‡ดๆ€ง๏ผŒ่ฎฉๅผ€ๅ‘่€…่ƒฝๅคŸๅฐฝๅฏ่ƒฝ่ดด่ฟ‘็œŸๅฎžๆต่งˆๅ™จ็š„็ฝ‘็ปœๆ ˆ่กŒไธบ๏ผŒๅŒ…ๆ‹ฌ TLS ๆกๆ‰‹็‰นๅพใ€HTTP/2 ่กŒไธบไปฅๅŠ Header ๆŽ’ๅˆ—ๆ–นๅผ็ญ‰ใ€‚

โœจ ไธ€ไธ‹ๆ˜ฏ`reqrio`็š„็‰น่‰ฒ๏ผš

* ้ซ˜ๅนถๅ‘ไธŽไฝŽๅ†…ๅญ˜ๅผ€้”€
* ๆตๅผๆ•ฐๆฎๅค„็†
* ไธบๅ่ฎฎ็ ”็ฉถ / ๅ็ˆฌ / ๆŒ‡็บนๆŽงๅˆถๆไพ›ๅŸบ็ก€่ƒฝๅŠ›
* ๆ”ฏๆŒTLSๆŒ‡็บน๏ผŒๅฏไปฅ้€š่ฟ‡TLSๆกๆ‰‹็š„ๅๅ…ญ่ฟ›ๅˆถใ€ja3ใ€ja4่ฎพ็ฝฎ(**ไป…่ฎข้˜…**),
* **ๆœ‰ๅบ่ฏทๆฑ‚ๅคด**(ๆŸฅ็œ‹[่ฏทๆฑ‚ๅคด้กบๅบ่กจ]https://github.com/xllgl2017/reqrio/blob/main/HEADER.md)๏ผŒๅ’Œๆต่งˆๅ™จไธ€่‡ด
* [**BoringSSL**]https://github.com/google/boringsslๆไพ›ๅŠ ่งฃๅฏ†/ๅฏ†็ ๅญฆ็ฎ—ๆณ•ใ€‚

## ๐ŸŒŠ ๆตๅผ่ฏทๆฑ‚ๅ’Œ่งฃๆž


`reqrio` ๆ˜ฏไธ€ไธช ไฝŽๆ‹ท่ด๏ผˆlow-copy๏ผ‰่ฏทๆฑ‚ๅ‘้€ๅผ•ๆ“Ž๏ผŒ็”จไบŽ้ซ˜ๆ•ˆๅœฐๅฐ† ็”จๆˆทๆ•ฐๆฎๆˆ–ๆ–‡ไปถๆ•ฐๆฎ ้€š่ฟ‡ TLS ๅŠ ๅฏ†ๅŽๅ‘้€ๅˆฐ TCPใ€‚`reqrio`ๅœจๅ‘้€ๆ—ถ๏ผŒ
ๅฏน็”จๆˆทไผ ๅ…ฅform-dataใ€jsonใ€text็ญ‰ๆ•ฐๆฎ่ฟ›่กŒ่ฝฌbytesๅ‚จๅญ˜๏ผŒ็„ถๅŽไป…ๅœจ่ฟ›ๅ…ฅ TLS ๅŠ ๅฏ†้˜ถๆฎตๆ—ถๅ‘็”Ÿไธ€ๆฌก copy๏ผŒ ๅ…ถไฝ™้˜ถๆฎตไป…ๅฏนๆ•ฐๆฎ่ฟ›่กŒ
borrow๏ผˆๅ€Ÿ็”จ๏ผ‰๏ผŒๅฏนๆ–‡ไปถไธŠไผ ๅˆ™้€š่ฟ‡into_reader่ฟ›่กŒ่ฏปๅ–๏ผŒๅ‡ๅฐๅ†…ๅญ˜ๅผ€้”€๏ผ›ๅœจๆŽฅๆ”ถๆ—ถ๏ผŒ็›ดๆŽฅๅฐ†่งฃๅฏ†ๅŽ็š„ๆ•ฐๆฎ็›ดๆŽฅๅ†™ๅ…ฅๅผ•ๆ“Žๅฑ‚็š„buffer๏ผŒ
็„ถๅŽ็”ฑๅผ•ๆ“Žๅฑ‚่ฟ›่กŒ่งฃๅŽ‹่งฃๆžๅŽ่ฟ”ๅ›žๅˆฐ็”จๆˆท

```text
โ”Œ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ Write โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”
โ”‚                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                 โ”‚
โ”‚       Url,Body โ”‚ ScReq  โ”‚ encode->bytes โ”‚  Request โ”‚ copy slice  โ”‚ fragment โ”‚ write โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ User โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ AcReq  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚  borrow  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚   TLS    โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚  TCP  โ”‚ โ”‚
โ”‚                โ”‚(Engine)โ”‚  into_reader  โ”‚  reader  โ”‚             โ”‚ Encrypt  โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                 โ”‚
โ”” โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”˜
โ”Œ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€  Read โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€  โ”€ โ”€ โ”€ โ”€ โ”
โ”‚                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                 โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” read  โ”‚   TLS    โ”‚ decrypt to โ”‚ ScReq  โ”‚  return         โ”‚
โ”‚ โ”‚  TCP  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ Fragment โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ AcReq  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ User  โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚ Decrypt  โ”‚            โ”‚(Engine)โ”‚ Response        โ”‚
โ”‚                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                 โ”‚
โ”” โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€ โ”€โ”˜

```


## ๐Ÿš€ ๅฟซ้€Ÿๅผ€ๅง‹


* ๅˆๅง‹ๅŒ–Session

```rust
use reqrio::*;
fn ff() {
    let headers = json::object! {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Accept-Encoding": "gzip, deflate, br, zstd",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Cookie": "__guid=15015764.1071255116101212729.1764940193317.2156; env_webp=1; _S=pvc5q7leemba50e4kn4qis4b95; QiHooGUID=4C8051464B2D97668E3B21198B9CA207.1766289287750; count=1; so-like-red=2; webp=1; so_huid=114r0SZFiQcJKtA38GZgwZg%2Fdit1cjUGuRcsIL2jTn4%2FE%3D; __huid=114r0SZFiQcJKtA38GZgwZg%2Fdit1cjUGuRcsIL2jTn4%2FE%3D; gtHuid=1",
        "Pragma": "no-cache",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "?1",
        "Upgrade-Insecure-Requests": 1,
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0",
        "sec-ch-ua": r#""Microsoft Edge";v="143", "Chromium";v="143", "Not A(Brand";v="24""#,
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": r#""Windows""#
    };
    let mut req = ScReq::new()
        //่ฎพ็ฝฎๆœ€้ซ˜HTTP็‰ˆๆœฌ๏ผŒ้ป˜่ฎคHTTP/1.1
        .with_alpn(ALPN::Http20)
        //Sessionๅ†…้ƒจ้ป˜่ฎคไธ่ฎพ็ฝฎไปปไฝ•่ฏทๆฑ‚ๅคด๏ผŒ้œ€่ฆๆ‰‹ๅŠจ่ฎพ็ฝฎ
        .with_header_json(headers).unwrap()
        //่ฎพ็ฝฎ่ฏทๆฑ‚่ถ…ๆ—ถๅ’Œๅฐ่ฏ•่ฏทๆฑ‚ๆฌกๆ•ฐ
        .with_timeout(Timeout::new_same(3000, 3));
}
```

* GET็š„็ฎ€ๅ•็คบไพ‹

```rust
use reqrio::*;

fn ff() {
    let mut req = ScReq::new();
    //get
    let mut res = req.get("https://www.baidu.com", None).unwrap();
    //่Žทๅ–็›ธๅบ”ๅคด
    let header = res.header();
    //่Žทๅ–็›ธๅบ”ไฝ“๏ผŒไธ็งปๅŠจๆ‰€ๆœ‰ๆƒ
    let body = res.decode_body().unwrap();
    //่Žทๅ–json๏ผŒ่ฝฌ็งปๆ‰€ๆœ‰ๆƒ
    let json = res.json().unwrap();
}
```

* ่กจๅ•ๆไบค็คบไพ‹

```rust
use reqrio::*;
fn ff() {
    let mut req = ScReq::new();
    let url = "https://www.baidu.com/api";
    let data = json::object! {
        "field1":"value1",
        "field2":"value2"
    };
    let resp = req.post(url, data.form()).unwrap();
}
```

* jsonๆไบค็คบไพ‹

```rust
use reqrio::*;
fn ff() {
    let mut req = ScReq::new();
    let url = "https://www.baidu.com/api";
    let data = json::object! {
        "field1":"value1",
        "field2":"value2"
    };
    let resp = req.post(url, data).unwrap();
}
```

* ๆไบคๅทฒๅฎž็Žฐ`Serialize`็š„struct็คบไพ‹

* ้œ€่ฆๆทปๅŠ serde็‰นๆ€ง

```rust
use reqrio::*;
use serde::Serialize;
fn ff() {
    let mut req = ScReq::new();
    #[derive(Serialize)]
    struct Data {
        field1: String,
        field2: bool
    }
    let url = "https://www.baidu.com/api";
    let resp = req.post(url, Body::json(&Data { field1: "value".to_string(), field2: false }).unwrap()).unwrap();
}
```