Rust Actix-Web线程不安全运动

Cal*_*orm 3 rust rust-actix actix-web

我正在尝试使用actix-web 1.0编写HTTP端点。我已经简化了该函数,以便仅返回传递给该函数的用户,但编译器仍会给出错误。

extern crate actix_web;
extern crate chrono;
extern crate futures;
extern crate listenfd;
#[macro_use]
extern crate serde_derive;
extern crate dotenv;
use actix_web::{error, web, App, Error, HttpResponse, HttpServer};
use futures::future::Future;

#[derive(Debug, Deserialize, Serialize)]
pub struct LoginUser {
    pub username: String,
    pub password: String,
}

pub fn login(
    login_user: web::Json<LoginUser>,
) -> impl Future<Item = HttpResponse, Error = error::BlockingError<Error>> {
    web::block(move || {
        let login_user = login_user.into_inner();
        let user = LoginUser {
            username: login_user.username,
            password: login_user.password,
        };
        Ok(HttpResponse::Ok().json(user))
    })
}

pub fn router(cfg: &mut web::ServiceConfig) {
    cfg.service(web::scope("/").service(web::resource("").route(web::get().to(login))));
}

fn main() -> std::io::Result<()> {
    HttpServer::new(move || App::new().configure(router))
        .bind("127.0.0.1:3000")?
        .run()
}
Run Code Online (Sandbox Code Playgroud)

这是我的cargo.toml。

[package]
name = "log"
version = "0.1.0"
authors = ["me@example.com"
edition = "2018"

[dependencies]
actix-files = "~0.1"
actix-web = "~1.0"
chrono = { version = "0.4.6", features = ["serde"] }
listenfd = "0.3"
diesel = {version = "1.4.1", features = ["postgres", "uuid", "r2d2", "chrono"]}
dotenv = "0.13"
failure = "0.1"
futures = "0.1"
scrypt = "0.2.0"
serde_derive="1.0"
serde_json="1.0"
serde="1.0"

Run Code Online (Sandbox Code Playgroud)

我收到编译错误

extern crate actix_web;
extern crate chrono;
extern crate futures;
extern crate listenfd;
#[macro_use]
extern crate serde_derive;
extern crate dotenv;
use actix_web::{error, web, App, Error, HttpResponse, HttpServer};
use futures::future::Future;

#[derive(Debug, Deserialize, Serialize)]
pub struct LoginUser {
    pub username: String,
    pub password: String,
}

pub fn login(
    login_user: web::Json<LoginUser>,
) -> impl Future<Item = HttpResponse, Error = error::BlockingError<Error>> {
    web::block(move || {
        let login_user = login_user.into_inner();
        let user = LoginUser {
            username: login_user.username,
            password: login_user.password,
        };
        Ok(HttpResponse::Ok().json(user))
    })
}

pub fn router(cfg: &mut web::ServiceConfig) {
    cfg.service(web::scope("/").service(web::resource("").route(web::get().to(login))));
}

fn main() -> std::io::Result<()> {
    HttpServer::new(move || App::new().configure(router))
        .bind("127.0.0.1:3000")?
        .run()
}
Run Code Online (Sandbox Code Playgroud)

我认为这是与使用login_userweb::block,但很难从错误判断。在Rust或actix中安全地异步使用请求参数的首选方法是什么?

小智 7

好吧,首先,HttpResponse没有实现Send。由于web::block()在线程池上运行闭包,这是一个问题。所以,你需要返回一个值,该值 Sendweb::block,然后创建一个HttpResponse从-使用and_then()的例子。

其次,您在路由器中使用web::get().to(login)。如果要调用返回a的函数,则Future必须为web::get().to_async(login)

第三,关闭web::block需要返回Result。由于您从不返回错误值,因此编译器无法推断错误类型。您需要给编译器一个提示。通常std::io::Error会这样做,所以返回Ok::<_, std::io::Error>(...value...)

第四,web::block返回BlockingError<E>。您可以用来from_err()将其映射到可以返回的内容。

因此,有了这些,代码的相关部分将看起来像:

pub fn login(
    login_user: web::Json<LoginUser>,
) -> impl Future<Item = HttpResponse, Error = Error> {
    web::block(move || {
        let login_user = login_user.into_inner();
        let user = LoginUser {
            username: login_user.username,
            password: login_user.password,
        };
        Ok::<_, std::io::Error>(user)
    })
        .from_err()
        .and_then(|user| HttpResponse::Ok().json(user))
}

pub fn router(cfg: &mut web::ServiceConfig) {
    cfg.service(web::scope("/").service(web::resource("").route(web::get().to_async(login))));
}
Run Code Online (Sandbox Code Playgroud)