下载
将文件下载到临时目录
创建一个临时目录TempDir::new
,并使用reqwest::get
在 HTTP,同步下载一个文件。
创建一个目标File
,姓名来自TempDir::path
内部的Response::url
,而io::copy
就把下载的数据复制到其中。临时目录,会run
函数返回时,自动移除。
# #[macro_use] # extern crate error_chain; extern crate reqwest; extern crate tempdir; use std::io::copy; use std::fs::File; use tempdir::TempDir; # # error_chain! { # foreign_links { # Io(std::io::Error); # HttpRequest(reqwest::Error); # } # } fn run() -> Result<()> { let tmp_dir = TempDir::new("example")?; let target = "https://www.rust-lang.org/logos/rust-logo-512x512.png"; let mut response = reqwest::get(target)?; let mut dest = { let fname = response .url() .path_segments() .and_then(|segments| segments.last()) .and_then(|name| if name.is_empty() { None } else { Some(name) }) .unwrap_or("tmp.bin"); println!("file to download: '{}'", fname); let fname = tmp_dir.path().join(fname); println!("will be located under: '{:?}'", fname); File::create(fname)? }; copy(&mut response, &mut dest)?; Ok(()) } # # quick_main!(run);
POST 一个文件,到 paste.rs
reqwest::Client
建立起到 https://paste.rs 的一个连接,遵循着reqwest::RequestBuilder
模式。调用Client::post
,加上 目标 URL 参数,RequestBuilder::body
通过读取文件,设置要发送的内容,以及RequestBuilder::send
会堵塞,直到文件上载并返回响应。read_to_string
返回响应,并显示在控制台中。
extern crate reqwest; # #[macro_use] # extern crate error_chain; # use std::fs::File; use std::io::Read; use reqwest::Client; # # error_chain! { # foreign_links { # HttpRequest(reqwest::Error); # IoError(::std::io::Error); # } # } fn run() -> Result<()> { let paste_api = "https://paste.rs"; let file = File::open("message")?; let mut response = Client::new().post(paste_api).body(file).send()?; let mut response_body = String::new(); response.read_to_string(&mut response_body)?; println!("Your paste is located at: {}", response_body); Ok(()) } # # quick_main!(run);
使用 HTTP range 标头,进行部分下载
使用reqwest::Client::head
,得到响应的内容长度。
然后,代码使用reqwest::Client::get
,在打印进度消息的同时,下载 10240 字节的内容。这个Range 标头指定块的大小和位置。
Range 标头在射频识别芯片中定义。
# #[macro_use] # extern crate error_chain; extern crate reqwest; use std::fs::File; use std::str::FromStr; use reqwest::header::{HeaderValue, CONTENT_LENGTH, RANGE}; use reqwest::StatusCode; # # error_chain! { # foreign_links { # Io(std::io::Error); # Reqwest(reqwest::Error); # Header(reqwest::header::ToStrError); # } # } # # struct PartialRangeIter { # start: u64, # end: u64, # buffer_size: u32, # } # # impl PartialRangeIter { # pub fn new(start: u64, end: u64, buffer_size: u32) -> Result<Self> { # if buffer_size == 0 { # Err("invalid buffer_size, give a value greater than zero.")?; # } # # Ok(PartialRangeIter { # start, # end, # buffer_size, # }) # } # } # # impl Iterator for PartialRangeIter { # type Item = HeaderValue; # # fn next(&mut self) -> Option<Self::Item> { # if self.start > self.end { # None # } else { # let prev_start = self.start; # self.start += std::cmp::min(self.buffer_size as u64, self.end - self.start + 1); # // 注意(unwrap): `HeaderValue::from_str` 仅在值不是 有效 ASCII 字符,才会失败 # // 因为,这个格式字符串是静态的,两个值是整数, # // 也就是说,失败不会发生。 # Some(HeaderValue::from_str(&format!("bytes={}-{}", prev_start, self.start - 1)).unwrap()) # } # } # } fn run() -> Result<()> { let url = "https://httpbin.org/range/102400?duration=2"; const CHUNK_SIZE: u32 = 10240; let client = reqwest::Client::new(); let response = client.head(url).send()?; let length = response .headers() .get(CONTENT_LENGTH) .ok_or("response doesn't include the content length")?; let length = u64::from_str(length.to_str()?).map_err(|_| "invalid Content-Length header")?; let mut output_file = File::create("download.bin")?; println!("starting download..."); for range in PartialRangeIter::new(0, length - 1, CHUNK_SIZE)? { println!("range {:?}", range); let mut response = client.get(url).header(RANGE, range).send()?; let status = response.status(); if !(status == StatusCode::OK || status == StatusCode::PARTIAL_CONTENT) { bail!("Unexpected server response: {}", status) } std::io::copy(&mut response, &mut output_file)?; } println!("Finished with success!"); Ok(()) } # # quick_main!(run);