reqwest v0.9.18的文档显示了以下发布文件的示例:
let file = fs::File::open("from_a_file.txt")?;
let client = reqwest::Client::new();
let res = client.post("http://httpbin.org/post")
.body(file)
.send()?;
reqwest v0.11的最新文档不再包含此示例,并且在调用
body()
时尝试构建它失败并出现以下错误:
the trait `From<std::fs::File>` is not implemented for `Body`
更新后的文件发送方法是什么?
reqwest
crate 之前的。如果您想使用确切的示例,则需要使用 reqwest::Client
,而不是 reqwest::blocking::Client
。这还需要启用 blocking
功能。
reqwest::blocking::RequestBuilder
的 body()
方法的文档中。
// reqwest = { version = "0.11", features = ["blocking"] }
use reqwest::blocking::Client;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = File::open("from_a_file.txt")?;
let client = Client::new();
let res = client.post("http://httpbin.org/post")
.body(file)
.send()?;
Ok(())
}
另请查看
reqwest
的 Form
和 RequestBuilder
的 multipart()
方法,因为例如有一个 file()
方法。
FramedRead
crate 中的 tokio-util
。连同 TryStreamExt
特征,来自 futures
箱子。
只需确保为
stream
启用 reqwest
功能,为 codec
启用 tokio-util
功能。
// futures = "0.3"
use futures::stream::TryStreamExt;
// reqwest = { version = "0.11", features = ["stream"] }
use reqwest::{Body, Client};
// tokio = { version = "1.0", features = ["full"] }
use tokio::fs::File;
// tokio-util = { version = "0.6", features = ["codec"] }
use tokio_util::codec::{BytesCodec, FramedRead};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = File::open("from_a_file.txt").await?;
let client = reqwest::Client::new();
let res = client
.post("http://httpbin.org/post")
.body(file_to_body(file))
.send()
.await?;
Ok(())
}
fn file_to_body(file: File) -> Body {
let stream = FramedRead::new(file, BytesCodec::new());
let body = Body::wrap_stream(stream);
body
}
如果您想使用
multipart/form-data
并且您正在使用 Tokio
这种方法已经可以帮助你了。
# Cargo.toml
[dependencies]
tokio = { version = "1.19", features = ["macros", "rt-multi-thread"] }
reqwest = { version = "0.11.11", features = ["stream","multipart","json"] }
tokio-util = { version = "0.7.3", features = ["codec"] }
multipart/form-data
use reqwest::{multipart, Body, Client};
use tokio::fs::File;
use tokio_util::codec::{BytesCodec, FramedRead};
async fn reqwest_multipart_form(url: &str) -> anyhow::Result<String> {
let client = Client::new();
let file = File::open(".gitignore").await?;
// read file body stream
let stream = FramedRead::new(file, BytesCodec::new());
let file_body = Body::wrap_stream(stream);
//make form part of file
let some_file = multipart::Part::stream(file_body)
.file_name("gitignore.txt")
.mime_str("text/plain")?;
//create the multipart form
let form = multipart::Form::new()
.text("username", "seanmonstar")
.text("password", "secret")
.part("file", some_file);
//send request
let response = client.post(url).multipart(form).send().await?;
let result = response.text().await?;
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_post_form_file() {
let url = "http://httpbin.org/post?a=1&b=true";
let get_json = reqwest_multipart_form(url).await.unwrap();
println!("users: {:#?}", get_json);
}
}
板条箱streamer可以为您做到这一点,并启用功能
hyper
:
use hyper::{Body, Request}:
let file = File::open("from_a_file.txt").unwrap();
let mut streaming = Streamer::new(file)
// optional, set the field name
// streaming.meta.set_name("txt");
// optional, set the file name
streaming.meta.set_filename("from_a_file.txt");
// length sent as a chunk, the default is 64kB if not set
streaming.meta.set_buf_len(1024 * 1024);
let body: Body = streaming.streaming();
// build a request
let request: Request<Body> = Request::post("<uri-here>").body(body).expect("failed to build a request");
streamer 将以 1 兆字节块的形式传输您的文件
示例代码
另请查看 reqwest 的 Form 和 RequestBuilder 的 multipart() 方法,因为其中有一个 file() 方法。
来自已接受的答案。为我工作。
use anyhow::Result;
use reqwest::{multipart, StatusCode};
#[tokio::test]
async fn upload_file()-> Result<()> {
let form = multipart::Form::new().file("file", "./Cargo.toml").await?;
let client = reqwest::Client::new();
let ret = client
.post("http://localhost:6688/api/files")
.multipart(form)
.send()
.await?;
assert_eq!(ret.status(), StatusCode::OK);
let chat_files = ret.json().await?;
Ok(chat_files)
}