追記(2021/08/26)
rustro_coreの0.47.0からByteStreamからSyncがなくなりました。なので一旦ローカルにファイルを作成してPartを作る必要があります。その部分は以下のようになります。
let file = std::fs::File.open("test.jpg");
let tokio_file = tokio::fs::File::from_std(file);
let stream = tokio_util::codec::FramedRead::new(tokio_file, tokio_util::codec::BytesCodec::new());
let Part::stream(reqwest::Body::wrap_stream(stream))
目的
AWSからダウンロードしたファイルを、HTTPのPOSTメソッドでアップロードしたいです。ローカルにファイルとして保存してアップロードするのはダサいので、ストリームで流してみました。
httpbin.orgはこちらが送ったデータをレスポンスで返してくれるので、自身が送ったパラメーターのデバッグなどで便利です。
プログラム
Cargo.toml
[package]
name = "upload_test"
version = "0.1.0"
edition = "2018"
[dependencies]
reqwest = { version = "~0.10.10", features = ["json", "stream"] }
rusoto_core = "~0.45.0"
rusoto_s3 = "~0.45.0"
serde_json = "~1.0.0"
tokio = { version = "~0.2", features = ["macros"] }
main.rs
use rusoto_core::Region;
use rusoto_s3::{GetObjectRequest, S3Client, S3};
use reqwest::multipart::{Form, Part};
type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;
#[tokio::main]
async fn main() -> Result<()> {
// S3からファイルをダウンロードする
let client = S3Client::new(Region::ApNortheast1);
let mut object = client
.get_object(GetObjectRequest {
bucket: "my_bucket".into(),
key: "target.txt".into(),
..Default::default()
})
.await?;
// ダウンロードしたファイルをマルチパートのストリームに渡す
let body = object.body.take().unwrap();
let part = Part::stream(reqwest::Body::wrap_stream(body));
let form = Form::new().part("file", part);
// POSTしてみる
let http_client = reqwest::Client::new();
let res = http_client
.post("http://httpbin.org/post")
.multipart(form)
.send()
.await?;
let json: serde_json::Value = res.json().await?;
println!("{:?}", json);
Ok(())
}
target.txt
予定表~①💖ハンカクだ
結果
{
"args": {},
"data": "",
"files": {},
"form": {
"file": "予定表~①💖ハンカクだ"
},
"headers": {
"Accept": "*/*",
"Content-Length": "227",
"Content-Type": "multipart/form-data; boundary=b7ff64c9dbddec30-c7bfea0ddcf8be1d-96b51cb6af4a31c7-c3e7a3069bab2189",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-601e515e-0fa5de530c1ea26d188d69e6"
},
"json": null,
"origin": "xxx.xxxx.xxx.xxx",
"url": "http://httpbin.org/post"
}