rust - 使用自定义 Rocket Responder 处理 RequestGuard 中的错误
问题描述
在使用 Rocket.rs 的 Web 服务器应用程序中,我使用了Responder
在我的 API 中实现的错误类型。此错误类型可确保统一呈现所有错误(如 RFC 7807 json)。
但是,我找不到在RequestGuards
. 似乎该from_request
函数导致Outcome
使用完全不同的模型,返回Outcome::Failure((Status, T))
错误。
如何确保这些请求防护中的错误以相同的 JSON 格式呈现?它甚至可以定制吗?
我曾尝试使用捕手,但这似乎并没有检索到任何错误信息。
解决方案
请注意,用户可以请求
Result<S, E>
和的类型Option<S>
来捕获Failure
s 并检索错误值。
在实施开始时
FromRequest
,定义type Error = JsonValue;
在
from_request
函数中,确保它返回request::Outcome<S, Self::Error>
你S
正在实现的目标。在
from_request
函数中,当您想要返回失败时,请执行类似的操作Outcome::Failure((Status::Unauthorized, json!({"error": "unauthorised"})))
,或者您想要返回的任何内容。在您的路由函数
Result<S, JsonValue>
中用作请求保护的类型,S
您在哪里实现。在您的路线中,使用match
它来匹配它Ok(S)
或Err(json_error)
例如。
可能有一种方法可以传递 的状态Outcome::Failure
,但我描述的解决方案意味着如果您使用自定义响应器,您将在响应器中设置状态,而不是基于Outcome::Failure
- 例如下面的代码。
这是一个应用于ApiKey
文档中的请求保护示例的示例,其中一个名为的示例自定义响应ApiResponse
程序设置了自己的状态:
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
#[macro_use]
extern crate serde_derive;
use rocket::Outcome;
use rocket::http::{ContentType, Status};
use rocket::request::{self, Request, FromRequest};
use rocket::response::{self, Responder, Response};
use rocket_contrib::json::{Json, JsonValue};
#[derive(Debug)]
pub struct ApiResponse {
pub json: JsonValue,
pub 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()
}
}
#[derive(Debug, Deserialize, Serialize)]
struct ApiKey(String);
/// Returns true if `key` is a valid API key string.
fn is_valid(key: &str) -> bool {
key == "valid_api_key"
}
impl<'a, 'r> FromRequest<'a, 'r> for ApiKey {
type Error = JsonValue;
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let keys: Vec<_> = request.headers().get("x-api-key").collect();
match keys.len() {
0 => Outcome::Failure((Status::BadRequest, json!({ "error": "api key missing" }))),
1 if is_valid(keys[0]) => Outcome::Success(ApiKey(keys[0].to_string())),
1 => Outcome::Failure((Status::BadRequest, json!({ "error": "api key invalid" }))),
_ => Outcome::Failure((Status::BadRequest, json!({ "error": "bad api key count" }))),
}
}
}
#[get("/sensitive")]
fn sensitive(key: Result<ApiKey, JsonValue>) -> ApiResponse {
match key {
Ok(_ApiKey) => ApiResponse {
json: json!({ "data": "sensitive data." }),
status: Status::Ok
},
Err(json_error) => ApiResponse {
json: json_error,
status: Status::BadRequest
}
}
}
我是 Rust 和 Rocket 的新手,所以这可能不是最好的解决方案。
推荐阅读
- algorithm - 在 kotlin 中以更好的方式在 kotlin 中编写条件逻辑
- groovy - 将解析的 T&Z 时间戳转换为毫秒
- java - 获取 Java 中计划的非阻塞操作的结果
- python - 在 Pandas 中更快地计算相关矩阵
- vue.js - Cypress JS 自定义命令在 VUE CLI 中不起作用
- java - JavaFX:更改文本区域中的光标
- .net - ImageMetadata 更改属性已损坏
- c# - GetString 总是返回默认语言资源
- css - 如何为使用 css `clip-path` 制作的三角形添加阴影?
- python - pycharm 为测试生成错误的目标路径