Rust actix-web 线程不安全移动
Rust actix-web thread unsafe movement
我正在尝试使用 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()
}
这是我的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"
我遇到编译错误
| web::block(move || {
| ^^^^^^^^^^ `(dyn std::any::Any + 'static)` cannot be sent between threads safely
我觉得和web::block
中使用了login_user
有关系,但是从错误中很难判断。在 Rust 或 actix 中安全地异步使用请求参数的首选方法是什么?
嗯,首先,HttpResponse
没有实现 Send
。由于 web::block()
在线程池上运行闭包,这是一个问题。因此,您需要 return 一个 是 Send
来自 web::block
的值,然后从中创建一个 HttpResponse
- 使用 [=例如 17=]。
其次,在您的路由器中您正在使用 web::get().to(login)
。如果要调用 return 为 Future
的函数,则需要 web::get().to_async(login)
.
第三,web::block
中的闭包需要returnResult
。由于您永远不会 return 错误值,因此编译器无法推断错误类型。你需要给编译器一个提示。通常 std::io::Error
就可以了,所以 return Ok::<_, std::io::Error>(...value...)
.
第四,web::block
return一个BlockingError<E>
。您可以使用 from_err()
将其映射到您可以 return.
的内容
因此,综上所述,您的代码的相关部分将如下所示:
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))));
}
我正在尝试使用 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()
}
这是我的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"
我遇到编译错误
| web::block(move || {
| ^^^^^^^^^^ `(dyn std::any::Any + 'static)` cannot be sent between threads safely
我觉得和web::block
中使用了login_user
有关系,但是从错误中很难判断。在 Rust 或 actix 中安全地异步使用请求参数的首选方法是什么?
嗯,首先,HttpResponse
没有实现 Send
。由于 web::block()
在线程池上运行闭包,这是一个问题。因此,您需要 return 一个 是 Send
来自 web::block
的值,然后从中创建一个 HttpResponse
- 使用 [=例如 17=]。
其次,在您的路由器中您正在使用 web::get().to(login)
。如果要调用 return 为 Future
的函数,则需要 web::get().to_async(login)
.
第三,web::block
中的闭包需要returnResult
。由于您永远不会 return 错误值,因此编译器无法推断错误类型。你需要给编译器一个提示。通常 std::io::Error
就可以了,所以 return Ok::<_, std::io::Error>(...value...)
.
第四,web::block
return一个BlockingError<E>
。您可以使用 from_err()
将其映射到您可以 return.
因此,综上所述,您的代码的相关部分将如下所示:
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))));
}