1

我正在使用 Actix-Web v1.0.7 在 Rust 中编写一个 Web 应用程序。我正在尝试创建一个可以访问路径参数并解析请求的 JSON 正文的路由处理程序。但是,到目前为止,我还没有这样做。

我尝试声明一个可以接受actix_web::HttpRequest作为参数的处理函数。match_info这使我可以毫无问题地使用方法访问路径参数。然后我尝试使用actix_web::web::Json::from_request方法(来自actix_web::FromRequesttrait 实现)解析 JSON 主体,该方法需要 2 个参数:

  1. &actix_web::HttpRequest
  2. &mut actix_web::dev::Payload

我的问题是获取actix_web::dev::Payload. 我尝试使用该actix_web::HttpRequest::take_payload方法(来自actix_web::HttpMessage特征实现),但特征实现将单位值声明为Stream有效负载内部,这意味着我被卡住了。我认为这是由于框架的异步特性,并且可能在调用处理程序时尚未收到请求正文。然而,这只是一个假设。

#[derive(Deserialize)]
struct Thing {
    // ...
}

type JsonThing = Json<Thing>;

fn handle(req: HttpRequest) -> impl IntoFuture {
    let id = req.match_info().query("id").parse::<usize>().unwrap();
    let mut payload = req.take_payload();
    JsonThing::from_request(&req, &mut payload)
        .and_then(|thing| {
            // ... 
            HttpResponse::Ok().finish()
        })
}

fn main() {
    let address = String::from("127.0.0.1:8080");
    let scope = web::scope("/scope")
        .route("/{id:\\d+}/path", web::put().to_async(handle));
    HttpServer::new(|| App::new().service(scope))
        .bind(address)
        .unwrap()
        .run()
        .unwrap();
}

我知道上面的代码片段无法编译并包含其他问题,但它传达了总体思路。我希望有一种方法可以从路径中获取 ID 参数的值,并且还能够解析同一请求的 JSON 正文,但到目前为止我还没有找到。

4

2 回答 2

0

Actix 为此使用提取器。定义要在处理程序中提取的内容:

#[derive(Deserialize, Serialize)] // <-- Note the Serialize for the json echo response
struct Thing {
    //...
}

type JsonThing = Json<Thing>;

fn handle(thing: JsonThing) -> impl Reponse {
    let id = req.match_info().query("id").parse::<usize>().unwrap();

    // echo the body back
    HttpResponse::Ok().json(thing)
}

您可以对id, 使用web::Query.

于 2019-09-22T20:00:58.523 回答
0

您将需要使用web::Path提取器id从路径中获取。多个提取器可以在同一个处理函数中使用。下面的示例适用于actix-web>= 3.0。

use actix_web::{error, web, App, HttpResponse, HttpServer, Responder};
use serde::Deserialize;

#[derive(Deserialize)]
struct Thing {
    name: String, // required string member.  This must exist in the request body's json.
    some_value: Option<String>, // optional member, can be missing from the request body.
    // ...
}

/// deserialize `Thing` from request's body and get `id` from path.
#[put("/{id:\\d+}/path")]
async fn handle(
  web::Path(id): web::Path<usize>, // web::Path extractor for 'id'
  web::Json(thing): web::Json<Thing> // web::Json extractor for json body.
) -> impl IntoFuture {
    // `web::Path(id)` uses Rust's pattern matching to "unwrap" the `id` value, so `id` is type `usize` here.
    // `web::Json(thing)` does the same "unwrapping", so `thing` is of type `Thing` here.

    // TODO: use 'id' and 'thing'
    HttpResponse::Ok().finish()
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let address = String::from("127.0.0.1:8080");
    HttpServer::new(|| {
        App::new()
          .service(handle)
    })
    .bind(address)?
    .run()
    .await
}
于 2020-12-17T08:57:22.293 回答