actix / actix-web

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.
https://actix.rs
Apache License 2.0
21.6k stars 1.67k forks source link

actix_web::web::Form<T>::extract(&HttpRequest) does not work as expected #1121

Closed YetAnotherMinion closed 5 years ago

YetAnotherMinion commented 5 years ago

I am having trouble using the form extractor manually following the example on the actix.rs website. I get a Parse error when trying to extract a Form from a request inside my handler function. The Form works fine when it is used as an argument to the handler function.

use futures::{IntoFuture, Future};
#[macro_use]
extern crate serde;

use actix_web::{
    get, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder, FromRequest,
};

#[derive(Deserialize)]
struct Register {
    a: String,
    b: String,
}

fn register(form: web::Form<Register>) -> impl Responder {
    format!("Hello {} from {}!", form.a, form.b)
}

fn register2(req: HttpRequest) -> impl Responder {
    match web::Form::<Register>::extract(&req).wait() {
        Ok(form) => format!("Hello {} from {}!", form.a, form.b),
        Err(err) => format!("error={:?}", err),
    }
}

fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_server=info,actix_web=info");
    env_logger::init();

    HttpServer::new(|| {
        App::new()
            .wrap(middleware::Logger::default())
            .route("/register", web::post().to(register))
            .route("/register2", web::post().to(register2))
    })
    .bind("127.0.0.1:9980")?
    .workers(1)
    .run()
}

The request to the handler that uses the Form as an argument succeeds:

$ curl localhost:9980/register --data "a=foo&b=bar"
Hello foo from bar!

The request to the handler than attempts to manually extract the Form fails.

$ curl localhost:9980/register2 --data "a=foo&b=bar"
error=Parse
fafhrd91 commented 5 years ago

Form get extracted from request payload.

You must use from_request method. https://github.com/actix/actix-web/blob/master/src/types/form.rs#L117

YetAnotherMinion commented 5 years ago

Thanks for the help!

I could not figure out how to construct a new actix_http::types::Payload enum from the actix_web::Payload extractor. However I found that I could use Result as an extractor in the arguments of a function and see the error message if the form failed to parse which is good enough for my use case.

fafhrd91 commented 5 years ago

You can access inner payload but change is not released yet