如何使Axum路由器处理返回不同的Content-Type响应?

7
例如,当用户访问http://127.0.0.1:8080/hello时,如果查询参数id为1,则返回一个纯文本响应。如果id为2,则返回一个json结构。
总结: | id(输入) | 状态码 | 内容类型 | 响应体 | | --- | --- | --- | --- | | 1 | 200 | application/json | {"name": "world"} | | 2 | 400 | text/plain | no such person |
struct HelloParam {
    id: u16,
}

struct HelloResponse {
    name: String,
}

async fn hello_get(Query(params): Query<HelloParam>) -> Response {
    // how to implement it? 
}

let router= Router::new().route("/hello", get(hello_get));

1个回答

5
请查看response模块开头的示例。Axum提供了多种不同的返回数据方式,以便自动设置Content-type头信息。 例如,如果您将String作为消息体返回,则Content-type将自动设置为"text/plain":
use axum::response::{IntoResponse, Response};

async fn returns_string() -> Response {
    String::from("Hello, world!").into_response()
}

还有一个自定义的 Json 结构,可以将实现了 serde::Serialize 的任何类型作为 JSON(并适当设置 Content-type 标头)返回。

use axum::response::{Json, IntoResponse, Response};
use serde::Serialize;

#[derive(Serialize)]
struct Hello {
    name: String,
}

async fn returns_json() -> Response {
    let hello = Hello {
        name: String::from("world"),
    };

    Json(hello).into_response()
}

因此,我们可以编写一个函数,根据请求的某些属性返回任一类型的响应。让我们根据“Accept”标头的值进行选择:

use axum::{
    http::{
        header::{ACCEPT, HeaderMap},
        status::StatusCode,
    },
    response::{Json, IntoResponse, Response},
};
use serde::Serialize;

#[derive(Serialize)]
struct Hello {
    name: String,
}

async fn heterogeneous_handle(headers: HeaderMap) -> Response {
    match headers.get(ACCEPT).map(|x| x.as_bytes()) {
        Some(b"text/plain") =>
            String::from("Hello, world!").into_response(),
        Some(b"application/json") => {
            let hello = Hello {
                name: String::from("world"),
            };
            Json(hello).into_response()
        },
        _ => StatusCode::BAD_REQUEST.into_response(),
    }
}


非常感谢。但是你能否向我展示如何使用查询参数作为heterogeneous_handle()的参数。如果我使用Query<HelloParam>作为参数,我无法编译它。 - progquester
Axum处理程序函数通过匹配其参数作为提取器来工作。在您的函数签名中具有Query(params): Query<HelloParam>参数意味着它将处理与HelloParam成员匹配的name=value对的请求。因此,如果一个请求带有查询字符串?id=1,则会使用相应设置调用您的处理程序函数类型为HelloParam的结构体params。然后,您只需匹配query.id的值而不是headers.get(ACCEPT)的值即可。 - d2718
非常感谢。但是编译错误是:特质约束fn(Query<HelloParam>) -> impl Future<Output = Response<http_body::combinators::box_body::UnsyncBoxBody<axum::body::Bytes, axum::Error>>> {heterogeneous_handle}: Handler<_, _>未满足 特质Handler<T, ReqBody>已实现为Layered<S, T>rustcE0277 libtest.rs(206, 45):此调用引入的约束要求 method_routing.rs(141, 16):axum::routing::get中的约束要求 - progquester
Axum有时候会给出难以理解的错误信息。如果您可以编辑您尝试过的内容,我可能能够帮到您。 - d2718
异步函数 heterogeneous_handle(Query(params): Query<HelloParam>) -> Response { match params.class.as_ref() { "json" => { let person = Person { name: "world".to_string(), }; Json(HelloResponse::Success(person)).into_response() } "text" => { "world".into_response()
} _ => StatusCode::BAD_REQUEST.into_response(), } }
- progquester
1
你可以将这句话编辑到你的问题中,这样就容易理解了吗? - d2718

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接