簡體   English   中英

如何使用 Actix-Web 從同一請求中提取路徑參數並解析 JSON 正文

[英]How do I extract path parameters and parse JSON body from the same request using Actix-Web

我正在使用 Actix-Web v1.0.7 在 Rust 中編寫 Web 應用程序。 我正在嘗試創建一個可以訪問路徑參數並解析請求的 JSON 正文的路由處理程序。 但是,到目前為止,我還沒有這樣做。

我嘗試聲明一個接受actix_web::HttpRequest作為參數的處理函數。 這使我可以使用match_info方法訪問路徑參數而不會出現任何問題。 然后我嘗試使用actix_web::web::Json::from_request方法(來自actix_web::FromRequest特征實現)解析 JSON 正文,該方法需要 2 個參數:

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

我的問題是獲取actix_web::dev::Payload 我嘗試使用actix_web::HttpRequest::take_payload方法(來自actix_web::HttpMessage trait 實現),但 trait 實現聲明了一個單位值作為有效負載內的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 正文,但到目前為止我還沒有找到。

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)
}

您可以使用web::Queryid執行相同操作。

您將需要使用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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM