如何使用 reqwest POST 一个文件?
How to POST a file using reqwest?
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 using async. If you want to use that exact example, then instead of reqwest::Client
, you need to use reqwest::blocking::Client
。这还需要启用 blocking
功能。
明确地说,您实际上仍然可以找到该示例,它只是位于 reqwest::blocking::RequestBuilder
's 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
and RequestBuilder
's multipart()
method, as there for instance is a file()
方法。
如果你确实想使用异步,那么你可以使用FramedRead
from the tokio-util
crate. Along with the TryStreamExt
trait, from the futures
crate。
只需确保为 reqwest
启用 stream
功能,为 tokio-util
启用 codec
功能。
// 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
}
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 using async. If you want to use that exact example, then instead of reqwest::Client
, you need to use reqwest::blocking::Client
。这还需要启用 blocking
功能。
明确地说,您实际上仍然可以找到该示例,它只是位于 reqwest::blocking::RequestBuilder
's 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
and RequestBuilder
's multipart()
method, as there for instance is a file()
方法。
如果你确实想使用异步,那么你可以使用FramedRead
from the tokio-util
crate. Along with the TryStreamExt
trait, from the futures
crate。
只需确保为 reqwest
启用 stream
功能,为 tokio-util
启用 codec
功能。
// 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
}