在 Rocket 中返回 HTTP 状态不是 200 的 JSON

Posted

技术标签:

【中文标题】在 Rocket 中返回 HTTP 状态不是 200 的 JSON【英文标题】:Return JSON with an HTTP status other than 200 in Rocket 【发布时间】:2019-07-18 20:01:50 【问题描述】:

我希望我的 Rocket API 有这样的路由:

#[post("create/thing", format = "application/json", data="<thing>")]

当客户端发送 "name": "mything" 时,一切都应该没问题,我知道该怎么做,但是当它发送 "name": "foo" 时,它应该回复如下内容:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

  "errors": [
    
      "status": "422",
      "title":  "Invalid thing name",
      "detail": "The name for a thing must be at least 4 characters long."
    
  ]

如何在 Rocket 中以 JSON 对象和不同于 200 的 HTTP 状态码之类的结果进行响应?

这是我迄今为止尝试过的:

impl FromRequest 我的 Thing 类型。这让我可以选择一个状态码,因为我可以编写自己的 from_request 函数,但我不能返回任何其他内容。 在this example 中注册一个错误捕获器,但这样我只能在没有上下文的情况下对一个 HTTP 状态代码做出反应。我的故障模式太多,无法为每种模式保留一个 HTTP 状态代码。

【问题讨论】:

rocket.rs/v0.4/guide/responses/#responses 有帮助吗? @hellow 我实际上调查了它并决定,它没有帮助,但现在我让它与 Responder impl 一起工作!将在下一小时内提供答案,谢谢。 我已经尝试过这样做,但我没有找到答案。也许那是不可能的。 【参考方案1】:

您需要构建响应。看看ResponseBuilder。您的回复可能如下所示。

use std::io::Cursor;
use rocket::response::Response;
use rocket::http::Status, ContentType;

let response = Response::build()
    .status(Status::UnprocessableEntity)
    .header(ContentType::Json)
    .sized_body(Cursor::new("Your json body"))
    .finalize();

【讨论】:

是的!就是这样!我自己提供了一个答案,其中包含所有工作代码。【参考方案2】:

在@hellow 的帮助下,我想通了。解决方案是为新结构ApiResponse 实现Responder 特征,该结构包含状态代码以及Json。这样我就可以做我想做的事了:

#[post("/create/thing", format = "application/json", data = "<thing>")]
fn put(thing: Json<Thing>) -> ApiResponse 
    let thing: Thing = thing.into_inner();
    match thing.name.len() 
        0...3 => ApiResponse 
            json: json!("error": "short": "Invalid Name", "long": "A thing must have a name that is at least 3 characters long"),
            status: Status::UnprocessableEntity,
        ,
        _ => ApiResponse 
            json: json!("status": "success"),
            status: Status::Ok,
        ,
    

这里是完整的代码:

#![feature(proc_macro_hygiene)]
#![feature(decl_macro)]

#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use rocket::http::ContentType, Status;
use rocket::request::Request;
use rocket::response;
use rocket::response::Responder, Response;
use rocket_contrib::json::Json, JsonValue;

#[derive(Serialize, Deserialize, Debug)]
pub struct Thing 
    pub name: String,


#[derive(Debug)]
struct ApiResponse 
    json: JsonValue,
    status: Status,


impl<'r> Responder<'r> for ApiResponse 
    fn respond_to(self, req: &Request) -> response::Result<'r> 
        Response::build_from(self.json.respond_to(&req).unwrap())
            .status(self.status)
            .header(ContentType::JSON)
            .ok()
    


#[post("/create/thing", format = "application/json", data = "<thing>")]
fn put(thing: Json<Thing>) -> ApiResponse 
    let thing: Thing = thing.into_inner();
    match thing.name.len() 
        0...3 => ApiResponse 
            json: json!("error": "short": "Invalid Name", "long": "A thing must have a name that is at least 3 characters long"),
            status: Status::UnprocessableEntity,
        ,
        _ => ApiResponse 
            json: json!("status": "success"),
            status: Status::Ok,
        ,
    


fn main() 
    rocket::ignite().mount("/", routes![put]).launch();

【讨论】:

从 Rocket 0.5.0 开始,rocket_contrib 将不再需要。您将能够 use rocket::serde::json::json, Json, Value;Value 替代 JsonValue 我没有设法将它与 Rocket 5.0rc1 一起使用。但使用 0.4.9 时它可以正常工作。谢谢!使用 Rocket 将 JSON 有效负载返回到 A. 中的错误状态痛苦。

以上是关于在 Rocket 中返回 HTTP 状态不是 200 的 JSON的主要内容,如果未能解决你的问题,请参考以下文章

由于cors,Angular 1.5响应状态返回NULL(-1)而不是503

Rocket - tilelink - Metadata

Spring Boot POST 请求返回 http 状态 405“方法不允许”而不是 HTTP 状态 404

返回使用 Rocket 和 Diesel (Rust) 在 PostgreSQL 中创建的单个记录

文件上传返回未定义的 HTTP 状态

Http 常用请求方式和返回状态码