asynchronous - 在 actix-web 中生成从多部分读取数据

标签 asynchronous rust actix-web

我试过 example of actix-multipartactix-web v3.3.2actix-multipart v0.3.0 .
举一个最小的例子,

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::spawnsave_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...
});
spawn返回 JoinHandle用于轮询任务。当您放下该句柄(不将其绑定(bind)到任何东西)时,该任务将“分离”,即它在后台运行。actix文档在这里不是特别有用,但是 actix使用 tokio引擎盖下的运行时。一个关键问题是在 tokio , 生成的任务不能保证完成 .执行者需要以某种方式知道它应该在那个 future 执行工作。在您的第二个示例中,生成的任务永远不会是 .await ed,它也不通过 channel 与任何其他任务进行通信。
最有可能的是,生成的任务永远不会被轮询,也不会取得任何进展。为了确保它完成,您可以.await JoinHandle (这将插入任务完成)或.await其他一些Future这取决于衍生任务中的工作(通常通过使用 channel )。

至于您的更一般的目标,工作已经在异步执行!最有可能,actix正在大致执行您在第二个示例中尝试执行的操作:收到请求后,它会生成一个任务来处理请求并反复轮询它(以及其他事件请求),直到它完成,然后发送响应。

关于asynchronous - 在 actix-web 中生成从多部分读取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66169240/

相关文章:

rust - Actix Web是否不处理发布请求?

c# - 将 async/await 与 DataReader 一起使用? (没有中间缓冲区!)

javascript - 异步加载javascript文件

node.js - async.forEach 不接受多个参数?

binding - 如何自动重写 bindgen 创建的 FFI 函数的签名?

rust - Rust traits 可以部分实现吗?

serialization - Rust bincode enum 二进制序列化

rust - 使用 actix-web 从 HTML 页面捕获 GET 和 POST 请求

java - Micronaut 是否需要异步编程?