json - 当内容类型不是 "application/json"时,如何在 Rocket 中解析 JSON 正文?

标签 json rust serde rust-rocket

我正在尝试解析此 JSON CSP Record由浏览器通过 POST 直接提交到嵌套结构中:

{"csp-report":{"document-uri":"http://localhost:8000/demo/","referrer":"","violated-directive":"img-src","effective-directive":"img-src","original-policy":"default-src 'self'; report-uri /.well-known/csp-violation","disposition":"report","blocked-uri":"https://www.google.com/logos/doodles/2020/googles-22nd-birthday-6753651837108550-law.gif","line-number":47,"source-file":"http://localhost:8000/demo/","status-code":200,"script-sample":""}}

发送以下 header :

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 442
Content-Type: application/csp-report
Host: localhost:8000
Origin: http://localhost:8000
Pragma: no-cache
Referer: http://localhost:8000/demo/
Sec-Fetch-Dest: report
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36

我关注了 Rocket JSON data guide ,但请求会生成一个 Unprocessable Entity (422),我不知道为什么。

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
struct Report {
    #[serde(with = "serde_with::json::nested")]
    csp_report: ReportBody,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
struct ReportBody {
    blocked_uri: String,
    disposition: String,
    document_uri: String,
    effective_directive: String,
    line_number: u128,
    original_policy: String,
    referrer: String,
    script_sample: String,
    source_file: String,
    status_code: u16,
    violated_directive: String,
}

#[post(
    "/.well-known/csp-violation",
    format = "application/csp-report",
    data = "<_report>"
)]
fn record(_report: Json<Report>) -> Status {
    Status::NoContent
}

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

我的猜测是,这是由于 header Content-Type: application/csp-report 造成的,我无法更改它,因为浏览器会自动发送报告。

最佳答案

来自 rocket_contrib 的 JSON 很方便,但不是必需的。您仍然可以使用 serde 自己从原始正文数据中解析 JSON(以下示例使用 async Rocket 完成)。这可能会绕过 header 的任何问题:

use rocket::Data;
...

#[post(
    "/.well-known/csp-violation",
    data = "<data>"
)]
async fn record(data: Data) -> Status {
    let body = match data.open(128.kilobytes()).stream_to_string().await {
        Ok(d) => d,
        Err(_) => return Status::NoContent, // or whatever error
    };
    let report: Report = match serde_json::from_str(&body) {
        Ok(a) => a,
        Err(_) => return Status::NoContent, // or whatever error
    };
    // do what you want with report here
    ...
    
    Status::NoContent
}

关于json - 当内容类型不是 "application/json"时,如何在 Rocket 中解析 JSON 正文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64110890/

相关文章:

json - JSON 模板中的转义值

recursion - 带外部变量的递归函数

rust - 使用 `Cell` 和 `RefCell` 进行内存或延迟评估的惯用方法

json - 错误[E0277] : the trait bound `Request<Body>: serde::ser::Serialize` is not satisfied

rust - 如何借用一个字段进行序列化,但在反序列化时创建它?

javascript - 如何使用 React 获取响应 header 中的 x-auth 值?

ios - 存储具有复杂数据结构的 JSON 文件以供以后使用的最佳方式是什么?

java - Spring boot jpa/hibernate 遇到列类型错误(json字段)

rust - 如何在 Rust 中创建一个引用 trait 实现的静态数组?

rust - 如何将 wasm 特定的宏与函数和结构分离