发表于 2024/04/01 19:44:38 [rust] 浏览次数:314
//! @Author: DengLibin
//! @Date: Create in 2023-10-20 14:11:17
//! @Description: http-client模块 使用reqwest
//!
use std::{
collections::HashMap,
path::Path,
thread,
};
use futures_util::StreamExt;
use reqwest::{
header::{HeaderMap, HeaderValue},
Body, Response,
};
use tokio::{
fs::{self, File},
io::AsyncWriteExt,
};
use tokio_util::codec::{BytesCodec, FramedRead};
#[derive(Debug, Clone, PartialEq)]
pub struct HttpError {
msg: String,
}
impl std::fmt::Display for HttpError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Message: {}", self.msg)
}
}
// 自定义结果
type HttpResult<T> = std::result::Result<T, HttpError>;
// 客户端
pub struct HttpClient {
user_agent: &'static str,
client: reqwest::Client,
}
impl HttpClient {
pub fn new() -> Self {
HttpClient {
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.46",
client: reqwest::Client::new()
}
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-20 19:59:44
/// @Description: 返回错误检查
pub async fn check_http_result(&self, resp: Response) -> HttpResult<Response> {
if !resp.status().is_success() {
let mut s = String::from("访问失败,状态码:");
s.push_str(resp.status().as_str());
s.push_str("\n");
s.push_str("内容:");
s.push_str(resp.text_with_charset("utf-8").await.unwrap().as_str());
return Result::Err(HttpError { msg: s });
}
return Result::Ok(resp);
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-20 20:15:45
/// @Description: 结果检查
pub fn check_result<T, E: std::fmt::Display>(&self, result: Result<T, E>) -> HttpResult<T> {
return match result {
Ok(r) => Result::Ok(r),
Err(err) => Result::Err(HttpError {
msg: err.to_string(),
}),
};
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-23 15:33:00
/// @Description: 根据文件路径获取文件名
pub fn get_filename(&self, filepath: &str) -> String {
let real_path = filepath.replace("\\", "/");
//获取文件名
let file_name_option = real_path.rfind("/");
return match file_name_option {
Some(idex) => String::from(&real_path[(idex + 1)..]),
None => real_path,
};
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-20 14:37:09
/// @Description: http请求
pub async fn get(&self, url: &str) -> HttpResult<String> {
// let r = reqwest::get(url).await;
// let mut headers = HeaderMap::new();
// headers.insert("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.46".parse().unwrap());
let r = self
.client
.get(url)
// .headers(headers)
.header("User-Agent", self.user_agent)
.send()
.await;
let r = self.check_result(r)?;
let r = self.check_http_result(r).await?;
let tr: Result<String, reqwest::Error> = r.text_with_charset("utf-8").await;
let s = self.check_result(tr)?;
return Result::Ok(s);
}
/// @Author: DengLibin
/// @Date: Create in 2024-03-20 15:15:25
/// @Description: 下载文件
pub async fn download_file_header(
&self,
url: &str,
headers: &HashMap<&'static str, String>,
file_path: &str,
) -> HttpResult<()> {
let mut header_map = HeaderMap::new();
for (k, v) in headers.into_iter() {
header_map.insert(*k, HeaderValue::from_str(v).unwrap());
}
let r = self
.client
.get(url)
.headers(header_map)
.header("User-Agent", self.user_agent)
.send()
.await;
let resp = self.check_result(r)?;
let resp = self.check_http_result(resp).await?;
//读取所有字节
let tr = resp.bytes().await;
let bytes = self.check_result(tr)?;
//创建文件
let file_r = File::create(file_path).await;
let mut file = self.check_result(file_r)?;
let b = bytes.as_ref();
//写入文件
let write_r = file.write_all(b).await;
let r = self.check_result(write_r)?;
return Ok(r);
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-20 17:19:53
/// @Description: 下载文件
/// @url: url
/// @file_path: 文件路径
pub async fn download_file(&self, url: &str, file_path: &str) -> HttpResult<()> {
let headers: HashMap<&'static str, String> = HashMap::new();
self.download_file_header(url, &headers, file_path).await
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-20 17:19:53
/// @Description: 下载文件
/// @url: url
/// @file_path: 文件路径
pub async fn download_by_stream(&self, url: &str, file_path: &str) -> HttpResult<()> {
let r = self
.client
.get(url)
// .headers(headers)
.header("User-Agent", self.user_agent)
.send()
.await;
let r = self.check_result(r)?;
let r = self.check_http_result(r).await?;
//获取字节流
let mut stream = r.bytes_stream();
//创建文件
let file_r = File::create(file_path).await;
let mut file = self.check_result(file_r)?;
//迭代
while let Some(chunk_result) = stream.next().await {
let chunk_bytes = self.check_result(chunk_result)?;
//写入文件
let write_r = file.write_all(&chunk_bytes).await;
let _ = self.check_result(write_r)?;
}
return Result::Ok(());
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-23 12:28:36
/// @Description:
pub async fn post_form(&self, url: &str, params: &[(&str, &str)]) -> HttpResult<String> {
// let params = [("foo", "bar"), ("baz", "quux")];
let r = self
.client
.post(url)
.form(¶ms)
// .headers(headers)
.header("User-Agent", self.user_agent)
.send()
.await;
let r = self.check_result(r)?;
let r = self.check_http_result(r).await?;
let tr: Result<String, reqwest::Error> = r.text_with_charset("utf-8").await;
let s = self.check_result(tr)?;
return Result::Ok(s);
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-23 13:38:53
/// @Description:
pub async fn post_json(&self, url: &str, params: &HashMap<&str, &str>) -> HttpResult<String> {
let r = self
.client
.post(url)
.json(¶ms)
// .headers(headers)
.header("User-Agent", self.user_agent)
.send()
.await;
let r = self.check_result(r)?;
let r = self.check_http_result(r).await?;
let tr: Result<String, reqwest::Error> = r.text_with_charset("utf-8").await;
let s = self.check_result(tr)?;
return Result::Ok(s);
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-23 13:53:13
/// @Description: 上传文件
pub async fn upload_file(
&self,
url: &str, //url
params: &[(&'static str, &'static str)], //文本参数
file_path: &str, //文件路径
) -> HttpResult<String> {
//获取文件名
let file_name = self.get_filename(file_path);
let file_r = fs::read(file_path).await;
let file = self.check_result(file_r)?;
//文件
let file_part = reqwest::multipart::Part::bytes(file).file_name(file_name);
//文件对象
let mut form = reqwest::multipart::Form::new().part("file", file_part);
//其他参数
for item in params {
form = form.text(item.0, item.1);
}
let r = self
.client
.post(url)
.multipart(form)
// .headers(headers)
.header("User-Agent", self.user_agent)
.send()
.await;
let r = self.check_result(r)?;
let r = self.check_http_result(r).await?;
let tr: Result<String, reqwest::Error> = r.text_with_charset("utf-8").await;
let s = self.check_result(tr)?;
return Result::Ok(s);
}
/// @Author: DengLibin
/// @Date: Create in 2023-10-23 15:31:07
/// @Description:
pub async fn upload_file_by_stream(
&self,
url: &str, //url
params: &[(&'static str, &'static str)], //文本参数
file_path: impl AsRef<Path>, //文件路径
) -> HttpResult<(String, String)> {
//获取文件名
let file_path = file_path.as_ref().as_os_str().to_str();
let file_path = if let Some(f) = file_path { f } else { "" };
let file_name = self.get_filename(file_path);
let mut t_name = "";
let thread = thread::current();
if let Some(t) = thread.name() {
t_name = t;
}
println!("[{}]上传文件{}", t_name, file_path);
let f = self.check_result(File::open(file_path).await)?;
let stream = FramedRead::new(f, BytesCodec::new());
//文件流
let stream_part =
reqwest::multipart::Part::stream(Body::wrap_stream(stream)).file_name(file_name);
//文件对象
let mut form = reqwest::multipart::Form::new().part("files", stream_part);
//其他参数
for item in params {
form = form.text(item.0, item.1);
}
let r = self
.client
.post(url)
.multipart(form)
// .headers(headers)
.header("User-Agent", self.user_agent)
.send()
.await;
let r = self.check_result(r)?;
let r = self.check_http_result(r).await?;
let tr: Result<String, reqwest::Error> = r.text_with_charset("utf-8").await;
let s = self.check_result(tr)?;
return Result::Ok((String::from(file_path), s));
}
}