从activx web中的多部分生成读取数据



我用actix-web v3.3.2actix-multipart v0.3.0尝试了activx multipart的例子。

举个最小的例子,

use actix_multipart::Multipart;
use actix_web::{post, web, App, HttpResponse, HttpServer};
use futures::{StreamExt, TryStreamExt};
#[post("/")]
async fn save_file(mut payload: Multipart) -> HttpResponse {
while let Ok(Some(mut field)) = payload.try_next().await {
let content_type = field.content_disposition().unwrap();
let filename = content_type.get_filename().unwrap();
println!("filename = {}", filename);
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
println!("Read a chunk.");
}
println!("Done");
}
HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(save_file))
.bind("0.0.0.0:8080")?
.run()
.await
}

这很好用,但我想异步处理表单数据。所以我改为尝试:

use actix_multipart::Multipart;
use actix_web::{post, web, App, HttpResponse, HttpServer};
use futures::{StreamExt, TryStreamExt};
#[post("/")]
async fn save_file(mut payload: Multipart) -> HttpResponse {
actix_web::rt::spawn(async move {
while let Ok(Some(mut field)) = payload.try_next().await {
let content_type = field.content_disposition().unwrap();
let filename = content_type.get_filename().unwrap();
println!("filename = {}", filename);
while let Some(chunk) = field.next().await {
let data = chunk.unwrap();
println!("Read a chunk.");
}
println!("Done");
}
});
HttpResponse::Ok().finish()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(save_file))
.bind("0.0.0.0:8080")?
.run()
.await
}

(将actix_web::rt::spawn添加到save_file。)

但这并没有起作用——消息"Done"从未打印出来。第二种情况下显示的"Read a chunk"的数量少于第一种情况,因此我猜测field.next().await在完成读取所有数据之前由于某种原因无法终止。

我对异步编程不太了解,所以我不知道field.next()为什么不能在actix_web::rt::spawn中工作。

我的问题是:为什么是actix_web::rt::spawn

当您进行此调用时:

actix_web::rt::spawn(async move {
// do things...
});

CCD_ 11返回用于轮询任务的CCD_。当您放弃该句柄(通过不将其绑定到任何东西)时,任务是";"分离";,即它在后台运行。

actix文档在这里没有特别的帮助,但是actix在后台使用了tokio运行时。一个关键问题是,在tokio中,派生的任务不能保证完成。执行人需要知道,不知何故,它应该在未来执行工作。在第二个示例中,派生的任务从来不是.awaited,也不通过通道与任何其他任务通信。

最有可能的是,生成的任务从未进行过轮询,也没有取得任何进展。为了确保它完成,您可以.awaitJoinHandle(它将驱动任务完成)或.await其他一些Future,它取决于派生任务中的工作(通常通过使用通道)。


至于您更普遍的目标,工作已经异步执行了!最有可能的是,actix正在做你在第二个例子中尝试做的事情:收到请求后,它产生一个处理请求的任务,并重复轮询它(以及其他活动请求),直到它完成,然后发送响应。

最新更新