common_uu 1.9.4

公共工具库
Documentation
// use crate::MyError;
use crate::{IResult, JsonV};
use reqwest::header::{HeaderMap, HeaderValue};
// use reqwest::Method;
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
// use std::path::Path;
// use std::str::FromStr;
use std::time::Duration;

fn get_haeders() -> Result<HeaderMap, String> {
    let mut haeders = HeaderMap::new();
    haeders.insert(
        "User-Agent",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0"
            .parse::<HeaderValue>()
            .map_err(|e| e.to_string())?,
    );
    haeders.insert(
        "Accept",
        "text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/webp,*/*;q=0.8"
            .parse::<HeaderValue>()
            .map_err(|e| e.to_string())?,
    );
    haeders.insert(
        "Accept-Language",
        "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2".parse::<HeaderValue>().map_err(|e| e.to_string())?,
    );
    // haeders.insert("Connection", "Close".parse()?);
    haeders.insert("Cache-Control", "no-cache".parse::<HeaderValue>().map_err(|e| e.to_string())?);
    Ok(haeders)
}

/// form表单提交数据
#[cfg(feature = "use_blocking")]
pub fn form(url: impl AsRef<std::path::Path>, form_params: HashMap<String, String>) -> IResult<String> {
    let mut form = reqwest::blocking::multipart::Form::new();
    for (k, v) in form_params {
        form = form.text(k, v);
    }
    let client = reqwest::blocking::Client::new();
    let resp = client.post(url.as_ref().to_str().unwrap_or_default()).multipart(form).send()?.text()?;
    Ok(resp)
}
/*#[test]
fn test_form() {
    let r = form("http://www.baidu.com", HashMap::new());
    println!("{:?}", r)
}*/

// 上传文件
/*pub fn upload_file(
    url: impl AsRef<Path>,
    form_params: HashMap<String, String>,
    file_path: impl AsRef<Path>,
) -> IResult<String> {
    let mut form = reqwest::blocking::multipart::Form::new().file("file", file_path)?;
    for (k, v) in form_params {
        form = form.text(k, v);
    }
    let client = reqwest::blocking::Client::new();
    let resp = client
        .post(url.as_ref().to_str().unwrap_or_default())
        .multipart(form)
        .send()?
        .text()?;
    Ok(resp)
}*/

/*#[test]
fn test_uplod_file() {
    let r = upload_file("http://www.baidu.com", HashMap::new(), file!());
    println!("{:?}", r)
}*/

#[allow(dead_code)]
fn get_haeders2(body: &str) -> IResult<HeaderMap> {
    let mut haeders = get_haeders()?;
    haeders.insert("Content-Length", body.len().to_string().parse()?);
    Ok(haeders)
}

pub enum Body {
    String(String),
    File(File),
    Null,
}

impl From<JsonV> for Body {
    fn from(v: JsonV) -> Self {
        if !v.is_null() {
            Self::String(v.to_string())
        } else {
            Self::Null
        }
    }
}

impl From<File> for Body {
    fn from(v: File) -> Self {
        Self::File(v)
    }
}

impl From<&str> for Body {
    fn from(v: &str) -> Self {
        Self::String(v.to_string())
    }
}

impl From<String> for Body {
    fn from(v: String) -> Self {
        Self::String(v)
    }
}

pub trait Headers {
    fn headers(self) -> HashMap<String, String>;
}

impl Headers for HashMap<String, String> {
    fn headers(self) -> HashMap<String, String> {
        self
    }
}

impl Headers for JsonV {
    fn headers(self) -> HashMap<String, String> {
        self.as_object()
            .map(|v| {
                let mut map = HashMap::new();
                for (k, v) in v {
                    map.insert(k.to_string(), v.as_str().unwrap_or_default().to_string());
                }
                map
            })
            .unwrap_or_default()
    }
}

// 使用cookie进行请求post
pub async fn req_with_header(url: String, input_headers: impl Headers, method: &str, body: impl Into<Body>) -> IResult<JsonV> {
    let mut haeders = HeaderMap::new();
    for (k, v) in input_headers.headers().iter() {
        let k = k.to_string();
        haeders.insert(reqwest::header::HeaderName::from_str(k.as_str())?, v.as_str().parse::<HeaderValue>().map_err(|e| e.to_string())?);
    }

    let client = reqwest::ClientBuilder::new().build()?;
    let method = match method.to_lowercase().trim() {
        "get" => reqwest::Method::GET,
        "post" => reqwest::Method::POST,
        _ => Err(format!("请求方法不受支持: {}", method))?,
    };
    let mut build = client.request(method, url).headers(haeders).timeout(Duration::from_secs(15));
    let body = body.into();
    match body {
        Body::File(mut f) => {
            let mut r = vec![];
            f.read_to_end(&mut r)?;
            build = build.body(r);
        }
        Body::String(s) => {
            build = build.body(s);
        }
        Body::Null => (),
    }
    debug!("req_with_header: {:?}", build);
    let text = build.send().await?.text().await?;
    let res = serde_json::from_str::<JsonV>(text.as_str()).unwrap_or_else(|_e| JsonV::String(text));
    return Ok(res);
}

#[cfg(test)]
mod test {
    use super::*;

    #[tokio::test]
    async fn test_req_with_header() -> IResult {
        let r = req_with_header("http://api.qichacha.com/ECIV4/Search?key=sdf&keyword=1".to_string(), JsonV::Null, "get", JsonV::Null).await?;
        println!("test_req_with_header: {}", r.to_string());
        Ok(())
    }
}

pub async fn req_with_header_t<T: DeserializeOwned>(url: String, input_headers: impl Headers, method: &str, body: impl Into<Body>) -> IResult<T> {
    let r = req_with_header(url, input_headers, method, body).await?;
    let r = serde_json::from_value(r)?;
    Ok(r)
}

pub async fn post_json<T: DeserializeOwned>(url: String, json_v: JsonV) -> IResult<T> {
    let text = reqwest::Client::new()
        .post(url.as_str())
        .json(&json_v)
        .headers(get_haeders()?)
        .header("Content-Type", "application/json;charset=utf-8")
        .timeout(Duration::from_secs(15))
        .send()
        .await?
        .text()
        .await?;
    let r = serde_json::from_str::<T>(text.as_str());
    return match r {
        Ok(v) => Ok(v),
        Err(e) => {
            warn!("{}", text);
            Err(e)?
        }
    };
}

pub async fn get_json<T: DeserializeOwned>(url: String) -> IResult<T> {
    let head = get_haeders()?;
    let text = reqwest::Client::new()
        .get(url.as_str())
        .headers(head)
        .header("Content-Type", "application/json;charset=utf-8")
        .timeout(Duration::from_secs(15))
        .send()
        .await?
        .text()
        .await?;
    let r = serde_json::from_str::<T>(text.as_str());
    return match r {
        Ok(v) => Ok(v),
        Err(e) => {
            warn!("{}", text);
            Err(e)?
        }
    };
}

/*#[test]
pub fn test_post_vec() {
    let body = r##"{"error_info":null,"data":{"data_id":null,"account_id":"96693efe7f3840e7b5c34cc90c33a9df","now_id":660,"type_title":"登录","created_datetime":"2020-12-23 12:08:59","error_info":null,"created_data":1608696539,"start_date":null,"end_date":null,"json_data":"正常"},"account":{"account_id":"96693efe7f3840e7b5c34cc90c33a9df","user_id":null,"company_name":null,"account_name":"91430105MA4LJQY047","account_password":"cszj131419","status":"帐户正常","last_get_data":null,"run_time":1608696509,"updated_time":1608696539,"created_time":1608696539}}"##;
    let r = post_json(
        "https://dsp.zgaic.com/fas/Tax/TaxpayerInformation".to_owned(),
        serde_json::from_str(body).unwrap(),
    )
    .await;
    println!("test_post_vec: {:?}", r);
}*/

pub async fn get(url: String) -> IResult<String> {
    let r = reqwest::Client::new().get(&url).headers(get_haeders()?).send().await?.text().await?;
    Ok(r)
}

pub async fn get_vec(url: String) -> IResult<Vec<u8>> {
    let r = reqwest::Client::new().get(&url).headers(get_haeders()?).send().await?.bytes().await?.to_vec();
    Ok(r)
}

/*#[test]
fn test_get_vec() -> IResult<()> {
    use std::fs::File;
    use std::io::Write;
    let bytes =
        get_vec("https://necaptcha.nosdn.127.net/d0cee769c8fa476b957af7f222972f6c.jpg".to_owned())
            .await;
    let mut file = File::create("测试.jpg").map_err(|e| format!("新建图片错误: {:?}", e))?;
    file.write_all(bytes.as_slice())
        .map_err(|e| format!("下载图片[write_all]错误: {:?}", e))?;
    Ok(())
}*/