5个版本
0.1.4 | 2022年4月27日 |
---|---|
0.1.3 | 2022年2月17日 |
0.1.2 | 2022年2月17日 |
0.1.1 | 2022年2月10日 |
0.1.0 | 2022年1月24日 |
#666 in HTTP服务器
2,852 每月下载量
在 2 个Crate中使用 (通过 coyote)
61KB
1.5K SLoC
ratpack:简单主义的HTTP框架(为rust-lang)
ratpack
在目标上被理想化为 sinatra (ruby) 框架的简洁性,并试图成为其他异步HTTP框架(如 tower、warp、axum、tide)的替代品。
ratpack
通过实现跨越处理器边界的“责任链”模式,试图承诺“任何处理器也可以是中间件”。总的来说,从第一个处理器返回的内容被提供给第二个处理器,然后返回给第三个处理器,直到所有处理器都处理完毕或收到错误。错误可以返回有效的状态码或HTTP 500(内部服务器错误)形式的纯文本错误。
ratpack 不是什么
- 复杂的:
ratpack
特别不是为具有大量路由或与HTTP协议(如SSE或Websockets)复杂交互的服务设计的。ratpack
非常专注于某种典型请求/响应周期。 - 冗长的:
ratpack
努力使其内部结构和您与之交互的方式都变得尽可能简单。这意味着您的请求处理器是您传递给名为compose_handler!
的宏的函数,您将其传递给路由调用,而且您可能不会花费时间实现复杂的、极其冗长的特质,甚至不需要对futures和async
有复杂的理解。 - 专注于一个平台:虽然目前我们仅直接支持
tokio
,但我们没有任何限制,不能进入smol
和async-std
的领域。大多数ratpack
对async
的使用都是通过tokio
在非常高的层次上利用的未来。
示例
这是一个示例,它将全局 应用程序状态 作为身份验证令牌验证中间件处理器,然后将其传递给问候处理器。问候处理器也可以在不进行身份验证的情况下在不同的端点重复使用,这也在示例中进行了演示。
注意:可以在 examples/auth-with-state.rs 中找到。也可以使用 cargo 运行:cargo run --example auth-with-state
。
use ratpack::prelude::*;
// We'll use authstate to (optionally) capture information about the token
// being correct. if it is Some(true), the user was authed, if None, there was no
// authentication performed.
#[derive(Clone)]
struct AuthedState {
authed: Option<bool>,
}
// All transient state structs must have an initial state, which will be
// initialized internally in the router.
impl TransientState for AuthedState {
fn initial() -> Self {
Self { authed: None }
}
}
// our authtoken validator, this queries the app state and the header
// `X-AuthToken` and compares the two. If there are any discrepancies, it
// returns `401 Unauthorized`.
//
// every handler & middleware takes and returns the same params and has the
// same prototype.
//
async fn validate_authtoken(
req: Request<Body>,
resp: Option<Response<Body>>,
_params: Params,
app: App<State, AuthedState>,
mut authstate: AuthedState,
) -> HTTPResult<AuthedState> {
if let (Some(token), Some(state)) = (req.headers().get("X-AuthToken"), app.state().await) {
authstate.authed = Some(state.clone().lock().await.authtoken == token);
Ok((req, resp, authstate))
} else {
Err(Error::StatusCode(StatusCode::UNAUTHORIZED))
}
}
// our `hello` responder; it simply echoes the `name` parameter provided in the
// route.
async fn hello(
req: Request<Body>,
_resp: Option<Response<Body>>,
params: Params,
_app: App<State, AuthedState>,
authstate: AuthedState,
) -> HTTPResult<AuthedState> {
let name = params.get("name").unwrap();
let bytes = Body::from(format!("hello, {}!\n", name));
if let Some(authed) = authstate.authed {
if authed {
return Ok((
req,
Some(Response::builder().status(200).body(bytes).unwrap()),
authstate,
));
}
} else if authstate.authed.is_none() {
return Ok((
req,
Some(Response::builder().status(200).body(bytes).unwrap()),
authstate,
));
}
Err(Error::StatusCode(StatusCode::UNAUTHORIZED))
}
// Our global application state; must be `Clone`.
#[derive(Clone)]
struct State {
authtoken: &'static str,
}
// ServerError is a catch-all for errors returned by serving content through
// ratpack.
#[tokio::main]
async fn main() -> Result<(), ServerError> {
let mut app = App::with_state(State {
authtoken: "867-5309",
});
app.get("/auth/:name", compose_handler!(validate_authtoken, hello));
app.get("/:name", compose_handler!(hello));
app.serve("127.0.0.1:3000").await?;
Ok(())
}
使用 curl
调用此服务会得到您预期的结果
% curl localhost:3000/erik
hello, erik!
% curl -D- localhost:3000/auth/erik
HTTP/1.1 401 Unauthorized
content-length: 0
date: Fri, 21 Jan 2022 18:29:03 GMT
% curl -D- -H "X-AuthToken: 867-5309" localhost:3000/auth/erik
HTTP/1.1 200 OK
content-length: 13
date: Fri, 21 Jan 2022 18:29:19 GMT
hello, erik!
更多信息 & 文档
有关更多信息,请参阅 文档。
作者
Erik Hollensbe [email protected]
许可证
BSD 3-Clause
依赖
~7–19MB
~259K SLoC