Crate boluo

source ·
Expand description

boluo是一个简单易用的异步网络框架。

§目录

§快速开始

新建项目:

cargo new demo && cd demo

添加依赖:

[dependencies]
boluo = "0.5"
tokio = { version = "1", features = ["full"] }

用以下内容覆盖src/main.rs

use boluo::response::IntoResponse;
use boluo::route::Router;
use boluo::server::Server;
use tokio::net::TcpListener;

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap();

    let app = Router::new().mount(hello);

    Server::new(listener).run(app).await.unwrap();
}

#[boluo::route("/", method = "GET")]
async fn hello() -> impl IntoResponse {
    "Hello, World!"
}

运行项目:

cargo run

访问服务:

curl http://127.0.0.1:3000/

§服务

Service特征表示一个接收请求并返回响应的异步函数。

§处理程序

处理程序是一个异步函数,它接受零个或多个提取器作为参数,并返回可以转换为响应的内容。

处理程序如下所示:

use boluo::body::Body;
use boluo::handler::handler_fn;
use boluo::response::IntoResponse;

// 返回空的`200 OK`响应的处理程序。
async fn empty() {}

// 返回带有纯文本主体的`200 OK`响应的处理程序。
async fn hello() -> &'static str {
    "Hello, World!"
}

// 返回带有请求主体的`200 OK`响应的处理程序。
//
// `Body`实现了`FromRequest`特征,可以作为提取器解析请求。并且也实现了
// `IntoResponse`特征,可以作为响应类型。
async fn echo(body: Body) -> impl IntoResponse {
    body
}

// 使用`handler_fn`函数将处理程序转换为`Service`。
let service = handler_fn(echo);

§提取器

提取器是实现了FromRequest特征的类型,可以根据Request创建实例。

use std::convert::Infallible;

use boluo::extract::FromRequest;
use boluo::http::{header, HeaderValue};
use boluo::request::Request;

// 从请求头中提取HOST的提取器。
struct Host(Option<HeaderValue>);

// 为提取器实现`FromRequest`特征。
impl FromRequest for Host {
    type Error = Infallible;

    async fn from_request(req: &mut Request) -> Result<Self, Self::Error> {
        let value = req.headers().get(header::HOST).map(|v| v.to_owned());
        Ok(Host(value))
    }
}

// 在处理程序中使用提取器从请求中提取数据。
async fn using_extractor(Host(host): Host) {
    println!("{host:?}")
}

§响应

任何实现IntoResponse特征的类型都可以作为响应。

use boluo::response::Html;
use boluo::response::IntoResponse;

// 返回带有纯文本主体的`200 OK`响应的处理程序。
async fn hello() -> &'static str {
    "Hello, World!"
}

// 返回显示`Hello, World!`的HTML页面的处理程序。
async fn html() -> impl IntoResponse {
    Html("<html><body>Hello, World!</body></html>")
}

§路由

Router用于设置哪些路径通向哪些服务。

use boluo::handler::handler_fn;
use boluo::route::Router;

#[boluo::route("/f", method = "GET")]
async fn f() -> &'static str {
    "f"
}

let ab = Router::new()
    .route("/a", handler_fn(|| async { "a" }))
    .route("/b", handler_fn(|| async { "b" }));

let cd = Router::new()
    .route("/c", handler_fn(|| async { "c" }))
    .route("/d", handler_fn(|| async { "d" }));

Router::new()
    // 路由。
    .route("/a", handler_fn(|| async { "a" }))
    .route("/b", handler_fn(|| async { "b" }))
    // 嵌套路由。
    .scope("/x", ab)
    // 将其他路由器的路由合并到当前路由器。
    .merge(cd)
    // 挂载宏定义路由。
    .mount(f);

§错误处理

错误和响应是分离的,可以在中间件对特定错误进行捕获,并将错误转换为自己想要的响应格式。

未经处理的错误到达服务器时,服务器将返回带有错误信息的500 INTERNAL_SERVER_ERROR响应。

use boluo::http::StatusCode;
use boluo::response::{IntoResponse, Response};
use boluo::route::{RouteError, RouteErrorKind, Router};
use boluo::service::ServiceExt;
use boluo::BoxError;

#[derive(Debug)]
struct MyError;

impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "some error message")
    }
}

impl std::error::Error for MyError {}

// 处理程序。
#[boluo::route("/", method = "GET")]
async fn throw_error() -> Result<(), MyError> {
    Err(MyError)
}

// 错误处理。
async fn handle_error(err: BoxError) -> Result<Response, BoxError> {
    // 处理框架抛出的路由错误,并自定义响应方式。
    if let Some(e) = err.downcast_ref::<RouteError>() {
        let status_code = match e.kind() {
            RouteErrorKind::NotFound => StatusCode::NOT_FOUND,
            RouteErrorKind::MethodNotAllowed => StatusCode::METHOD_NOT_ALLOWED,
        };
        return Ok((status_code, format!("{status_code}")).into_response()?);
    }
    if let Some(_) = err.downcast_ref::<MyError>() {
        // 记录错误、转为响应等等。
    }
    Err(err)
}

Router::new().mount(throw_error).or_else(handle_error);

§中间件

中间件是实现了Middleware特征的类型,可以调用ServiceExt::with函数将中间件 应用于Service

中间件实际上是将原始服务转换为新的服务。

use boluo::data::Extension;
use boluo::handler::handler_fn;
use boluo::service::ServiceExt;

async fn extension(Extension(text): Extension<&'static str>) -> &'static str {
    text
}

let service = handler_fn(extension);
let service = service.with(Extension("Hello, World!"));

Re-exports§

Modules§

  • HTTP主体。
  • 通用数据类型。
  • 从请求中提取数据的类型和特征。
  • fsfs
    静态文件服务。
  • 可用于处理请求并返回响应的异步函数。
  • http库的重新导出。
  • listenerlistener
    监听器的特征和相关类型的定义。
  • 中间件的特征和相关类型的定义。
  • multipartmultipart
    用于解析文件上传中常用的multipart/form-data格式数据。
  • HTTP请求。
  • HTTP响应。
  • 将请求转发到服务的类型和特征。
  • serverserver and (http1 or http2)
    HTTP服务器。
  • 服务的特征和相关类型的定义。
  • wsws
    处理WebSocket连接。

Type Aliases§

  • 类型擦除的错误类型别名

Attribute Macros§

  • 为处理程序添加请求路径和方法。