用Rust写一个批量HTTP REST请求工具

2022 Nov 08 See all posts


把一个日常用的小工具用Rust重写一下,以前都是快速写个Python脚本自己跑,但是现在要给同事用,同事的电脑是Mac M1,不想装Python,Python程序打出来的包太大了,放弃。

GoRust是不错的选择,生成的可执行文件小,还可以很方便跨平台打包。本着哪壶不开提哪壶的原则,选用Rust吧。

功能很简单,批量发http rest请求,主要涉及到从配置文件读取cookie信息以及各种配置如限速,从业务文件读取业务参数,然后分批发HTTP REST请求。

核心代码如下:

async fn do_bat_del(config: &BasicConfig) -> bool {
    const UID_FILE_NAME: &str = "uid_list.txt";
    let lines = read_lines_to_list(UID_FILE_NAME).unwrap_or_else(|err| {
        error!("Failed to read file: {:?}, {}", UID_FILE_NAME, err);
        Vec::new()
    });
    match req::req_proc::get_client(&config.cookie_str) {
        Ok(client) => {
            let mut i: u32 = 0;
            let semaphore = Semaphore::new(1);
            for line in lines {
                match line.parse::<u64>() {
                    Ok(uid) => {
                        let permit = semaphore.acquire().await.unwrap();
                        req::req_proc::delete(&client, &config.host_url, uid)
                            .await
                            .map(|v| info!("{}, success for uid: {:?}, {}", i + 1, uid, v))
                            .unwrap_or_else(|err| error!("{}, fail for uid: {:?}, {}", i + 1, uid, err));
                        drop(permit);
                    }
                    Err(err) => {
                        error!("{}, illegal uid: {:?}, {}", i + 1, line, err)
                    }
                }
                i += 1;

                if i % config.max_ops == 0 {
                    info!("Start sleep {} seconds", config.sleep_secs_after_max_ops);
                    tokio::time::sleep(time::Duration::from_secs(config.sleep_secs_after_max_ops)).await;
                };
            }
        }
        Err(err) => {
            error!("Failed to initialize HttpClient, {}", err);
        }
    };
    true
}
use std::{collections::HashMap, time::Duration};

use super::ReqError;

pub fn get_client(cookie: &str) -> Result<reqwest::Client, ReqError> {
    let mut headers = http::HeaderMap::new();
    let cookie_head_value = http::header::HeaderValue::from_str(cookie);
    match cookie_head_value {
        Ok(cookie) => {
            headers.insert(http::header::COOKIE, cookie);
            let client = reqwest::Client::builder()
                .timeout(Duration::from_secs(10))
                .cookie_store(true)
                .default_headers(headers)
                .build();
            Ok(client?)
        }
        Err(_) => Err(ReqError::CookieFmt()),
    }
}

pub async fn delete(
    client: &reqwest::Client,
    host_url: &str,
    user_id: u64,
) -> Result<serde_json::value::Value, ReqError> {
    let url = host_url.to_owned() + "/xxx/delete.vpage";
    let mut params = HashMap::new();
    params.insert("userId", user_id.to_string());
    let request_builder = client.post(url).form(&params);
    let resp = request_builder.send().await?;
    let text_value = &resp.text().await?;
    let json_value = serde_json::from_str(&text_value);
    match json_value {
        Result::Ok(val) => Ok(val),
        Result::Err(err) => {
            // error!("Fail to parse json:{}, {}",&text_value, err);
            // error!("Please update a valid cookie");
            Err(ReqError::SerdeJson(err))
        }
    }
}


#[cfg(test)]
mod test {}

跨平台编译

M1 Apple Mac:

docker run --rm \
    --volume "${PWD}":/root/src \
    --workdir /root/src \
      joseluisq/rust-linux-darwin-builder:1.65.0 \
        sh -c "cargo build --release --target aarch64-apple-darwin"

Intel Mac

docker run --rm \
    --volume "${PWD}":/root/src \
    --workdir /root/src \
      joseluisq/rust-linux-darwin-builder:1.65.0 \
        sh -c "cargo build --release --target x86_64-apple-darwin"

Windows

docker run --rm -it -v "${PWD}":/io -w /io messense/cargo-xwin \
  sh -c "cargo xwin build --release --target x86_64-pc-windows-msvc"

感想

2023-03-25新增Delphi


Back to top