当内容类型不是 "application/json" 时,如何在 Rocket 中解析 JSON body?
How do I parse a JSON body in Rocket when the content type is not "application/json"?
我正在尝试将浏览器直接通过 POST
提交的 JSON CSP Record 解析为嵌套结构:
{"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
我无法更改,因为浏览器会自动发送报告。
JSON 来自 rocket_contrib 是一种方便,但不是必需的。您仍然可以使用 serde 自己从原始 body 数据中解析 JSON(以下示例是使用 async Rocket 完成的)。这可能会绕过 headers:
的任何问题
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
}
我正在尝试将浏览器直接通过 POST
提交的 JSON CSP Record 解析为嵌套结构:
{"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
我无法更改,因为浏览器会自动发送报告。
JSON 来自 rocket_contrib 是一种方便,但不是必需的。您仍然可以使用 serde 自己从原始 body 数据中解析 JSON(以下示例是使用 async Rocket 完成的)。这可能会绕过 headers:
的任何问题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
}