19个版本 (11个稳定版本)
2.3.3 | 2024年4月8日 |
---|---|
2.3.0 | 2024年3月17日 |
1.0.1 | 2024年2月17日 |
0.4.3 | 2024年2月12日 |
0.2.2 |
|
#75 in HTTP客户端
每月120次下载
7.5MB
2K SLoC
curl-http-client
这是curl-rust crate中的Easy2的包装器,用于方便使用,并可以使用async-curl crate以异步方式执行,该crate使用actor模型(消息传递)来实现非阻塞I/O。
异步示例
获取请求
use async_curl::CurlActor;
use curl_http_client::*;
use http::{Method, Request};
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let actor = CurlActor::new();
let collector = Collector::Ram(Vec::new());
let request = Request::builder()
.uri("<SOURCE URL>")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.request(request).unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
}
POST请求
use async_curl::CurlActor;
use curl_http_client::*;
use http::{Method, Request};
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let actor = CurlActor::new();
let collector = Collector::Ram(Vec::new());
let request = Request::builder()
.uri("<TARGET URL>")
.method(Method::POST)
.body(Some("test body".as_bytes().to_vec()))
.unwrap();
let response = HttpClient::new(collector)
.request(request).unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
}
下载文件
use std::path::PathBuf;
use async_curl::CurlActor;
use curl_http_client::*;
use http::{Method, Request};
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let actor = CurlActor::new();
let collector = Collector::File(FileInfo::path(PathBuf::from("<FILE PATH TO SAVE>")));
let request = Request::builder()
.uri("<SOURCE URL>")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.request(request)
.unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
Ok(())
}
上传文件
use std::{fs, path::PathBuf};
use async_curl::CurlActor;
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let file_to_be_uploaded = PathBuf::from("<FILE PATH TO BE UPLOADED>");
let file_size = fs::metadata(file_to_be_uploaded.as_path()).unwrap().len() as usize;
let actor = CurlActor::new();
let collector = Collector::File(FileInfo::path(file_to_be_uploaded));
let request = Request::builder()
.uri("<TARGET URL>")
.method(Method::PUT)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.upload_file_size(FileSize::from(file_size)).unwrap()
.request(request).unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
}
并发
use async_curl::CurlActor;
use curl_http_client::*;
use futures::future;
use http::{HeaderMap, Method, Request};
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
const NUM_CONCURRENT: usize = 5;
let actor = CurlActor::new();
let mut handles = Vec::new();
for _n in 0..NUM_CONCURRENT {
let actor = actor.clone();
let handle = tokio::spawn(async move {
let collector = Collector::Ram(Vec::new());
let request = Request::builder()
.uri("https://www.rust-lang.net.cn/")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.request(request)
.unwrap()
.nonblocking(actor)
.perform()
.await
.unwrap();
println!("Response: {:?}", response);
});
handles.push(handle);
}
let results: Vec<Result<_, _>> = future::join_all(handles).await;
for (_i, result) in results.into_iter().enumerate() {
result.unwrap();
}
}
恢复下载文件
use std::fs;
use std::path::PathBuf;
use async_curl::CurlActor;
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let actor = CurlActor::new();
let save_to = PathBuf::from("<FILE PATH TO SAVE>");
let collector = Collector::File(FileInfo::path(save_to.clone()));
let partial_download_file_size = fs::metadata(save_to.as_path()).unwrap().len() as usize;
let request = Request::builder()
.uri("<SOURCE URL>")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.resume_from(BytesOffset::from(partial_download_file_size)).unwrap()
.request(request).unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
}
向不同任务发送下载速度信息的文件下载
use std::path::PathBuf;
use async_curl::CurlActor;
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use tokio::sync::mpsc::channel;
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let (tx, mut rx) = channel(1);
let actor = CurlActor::new();
let file_info = FileInfo::path(PathBuf::from("<FILE PATH TO SAVE>")).with_transfer_speed_sender(tx);
let collector = Collector::File(file_info);
let handle = tokio::spawn(async move {
while let Some(speed) = rx.recv().await {
println!("Download Speed: {} kB/s", speed.as_bytes_per_sec());
}
});
let request = Request::builder()
.uri("<SOURCE URL>")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.request(request).unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
handle.abort();
}
向不同任务发送上传速度信息的文件上传
use std::{fs, path::PathBuf};
use async_curl::CurlActor;
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use tokio::sync::mpsc::channel;
use url::Url;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let (tx, mut rx) = channel(1);
let file_to_be_uploaded = PathBuf::from("<FILE PATH TO BE UPLOADED>");
let file_size = fs::metadata(file_to_be_uploaded.as_path()).unwrap().len() as usize;
let actor = CurlActor::new();
let file_info = FileInfo::path(file_to_be_uploaded).with_transfer_speed_sender(tx);
let collector = Collector::File(file_info);
let handle = tokio::spawn(async move {
while let Some(speed) = rx.recv().await {
println!("Upload Speed: {} kB/s", speed.as_bytes_per_sec());
}
});
let request = Request::builder()
.uri("<TARGET URL>")
.method(Method::PUT)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.upload_file_size(FileSize::from(file_size)).unwrap()
.request(request).unwrap()
.nonblocking(actor)
.perform()
.await.unwrap();
println!("Response: {:?}", response);
handle.abort();
}
同步示例
获取请求
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let collector = Collector::Ram(Vec::new());
let request = Request::builder()
.uri("<SOURCE URL>")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.request(request)?
.blocking()
.perform()?;
println!("Response: {:?}", response);
Ok(())
}
POST请求
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let collector = Collector::Ram(Vec::new());
let request = Request::builder()
.uri("<TARGET URL>")
.method(Method::POST)
.body(Some("test body".as_bytes().to_vec()))
.unwrap();
let response = HttpClient::new(collector)
.request(request)?
.blocking()
.perform()?;
println!("Response: {:?}", response);
Ok(())
}
下载文件
use std::path::PathBuf;
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let collector = Collector::File(FileInfo::path(PathBuf::from("<FILE PATH TO SAVE>")));
let request = Request::builder()
.uri("<SOURCE URL>")
.method(Method::GET)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.request(request)?
.blocking()
.perform()?;
println!("Response: {:?}", response);
Ok(())
}
上传文件
use std::{fs, path::PathBuf};
use curl_http_client::*;
use http::{HeaderMap, Method, Request};
use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file_to_be_uploaded = PathBuf::from("<FILE PATH TO BE UPLOADED>");
let file_size = fs::metadata(file_to_be_uploaded.as_path()).unwrap().len() as usize;
let collector = Collector::File(FileInfo::path(file_to_be_uploaded));
let request = Request::builder()
.uri("<TARGET URL>")
.method(Method::PUT)
.body(None)
.unwrap();
let response = HttpClient::new(collector)
.upload_file_size(FileSize::from(file_size))?
.request(request)?
.blocking()
.perform()?;
println!("Response: {:?}", response);
Ok(())
}
依赖关系
~15–25MB
~397K SLoC