如何在 Rocket Rust REST API 中将 X-Total-Count 添加到 header 响应?

How to add X-Total-Count to header response in Rocket Rust REST API?

我用 Rust 创建了一个 REST API 并且 Rocket 与 swagger 一起工作。 现在我正在尝试使用 React react-admin 来精确地使用这个 API。一切正常,直到我需要调用出现著名 X-Total-Count 问题的列表,但我无法解决它,可能是由于缺乏 Rust 经验。

这是消息 “HTTP 响应 中缺少 X-Total-Count header。jsonServer 数据提供程序期望资源列表的响应包含此 header 以及总计构建分页的结果数。如果您使用的是 CORS,您是否在 Access-Control-Expose-Headers header"

中声明了 X-Total-Count

这是我的回复header

HTTP/1.1 200 OK
Content-Type: application/json
Server: Rocket
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: x-total-count, content-length, server
Content-Length: 45
Date: Wed, 02 Jun 2021 04:38:21 GMT

我尝试了很多东西,在 header 中追加 X-Total-Count: cant_registries 没有任何幸运

这是我的main.rs。欢迎任何提示、帮助和修改。提前致谢

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_okapi;

use rocket::request::Request;
use rocket::response::{self, Response, Responder};
use rocket::http::ContentType;
use rocket::http::Header;

use rocket::request::{Form, FromForm};
use rocket_contrib::json::Json;
use rocket_okapi::swagger_ui::*;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use rocket::http::Method;
use std::env;
use std::process::Command;
use rocket_cors::{
    AllowedOrigins,
    Cors, CorsOptions,
};

#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
struct User {
    user_id: u64,
    username: String
}

// impl<'r> Responder<'r> for User {
//    fn respond_to(self, _: &Request) -> response::Result<'r> {
//        Response::build()
//            .header(Header::new("X-Total-Count", "1"))
//            .ok()
//    }
// }

fn example_email() -> &'static str {
    "test@example.com"
}

fn make_cors() -> Cors {
    let allowed_origins = AllowedOrigins::some_exact(&[
        "http://localhost:3000",
    ]);

    CorsOptions { // 5.
        allowed_origins,
        expose_headers: [ "x-total-count", "content-length","server" ]
        .iter()
            .map(ToString::to_string)
            .collect(), 
        allowed_methods: vec![Method::Get, Method::Post, Method::Patch].into_iter().map(From::from).collect(),
        allow_credentials: false,
        ..Default::default()
    }
        .to_cors()
        .expect("error while building CORS")
}

/// # Get all users
#[openapi]
#[get("/user")]
fn get_all_users() -> Json<Vec<User>> {
    Json(vec![User {
        user_id: 88,
        username: "goja288".to_owned(),
    }])
    

}

fn main() {
    rocket::ignite()
        .mount(
            "/",
            routes_with_openapi![
                get_all_users,
            ],
        )
        .mount(
            "/swagger-ui/",
            make_swagger_ui(&SwaggerUIConfig {
                url: "../openapi.json".to_owned(),
                ..Default::default()
            }),
        ).attach(make_cors())
        .launch();
}

尝试通过包装 Json<Vec<User>> 将 header 添加到响应中(实现 Responder trait) with a custom struct (see Rocket docs on custom responders:

#[derive(Debug)]
struct JsonWithTotalCount<T: Serialize> {
    data: Json<Vec<T>>,
    total_count_header: Header<'static>,
}

impl<T: Serialize> JsonWithTotalCount<T> {
    pub fn new(data: Vec<T>) -> Self {
        Self {
            total_count_header: Header::new("X-Total-Count", data.len().to_string()),
            data: Json(data),
        }
    }
}

impl<'r, T: Serialize> Responder<'r> for JsonWithTotalCount<T> {
    fn respond_to(self, request: &Request) -> response::Result<'r> {
        let mut build = Response::build();
        build.merge(self.data.respond_to(request)?);
        build.header(self.total_count_header);
        build.ok()
    }
}

并在您的 get_all_users 函数中使用它:

/// # Get all users
#[get("/user")]
fn get_all_users() -> JsonWithTotalCount<User> {
    JsonWithTotalCount::new(vec![User {
        user_id: 88,
        username: "goja288".to_owned(),
    }])
}