[译] 使用 Axum, Hyper, Tonic, 和 Tower 构建 WEB/GRPC 应用

原文地址: Part1Part2Part3

我在 Rust 中尝试过各种 Web 服务器和框架, 并发现它们各有优点和缺点. 最近, 我使用了FP Complete的解决方案Zehut (我下次再写博客) 需要将Web前端和gRPC服务器结合起来. 我使用了 Hyper、Tonic 和我自己开发的一个名为 routetype 的最小库. 虽然它能够工作, 但我感到有些失望。直接使用 Hyper,即使使用最小的路由类型层,也感觉只是临时的方案.

当我最近看到 Axum 发布, 它似乎满足了我很多需求, 尤其是它宣称支持 Tonic. 我决定进行一次实验, 用 Axum 替换我之前使用的直接 Hyper + routetype 方式. 总体而言, 这种方法可行,但 (就像我之前使用 routetype 工作一样), Hyper 和 Tower API 一起使用会有一定的难度.

我一直想写一些有关 Hyper+Tower 的博客文章/教程/经验报告. 因此, 我决定利用这个机会逐步介绍这四个库(Tower、Hyper、Axum 和 Tonic), 特别是对于混合了 Web/gRPC 的应用程序. 但需要说明的内容比我预期的要多, 为了阅读方便我分为四个部分:

  • Tower 总览
  • 了解 Hyper 和第一次使用 Axum
  • 使用 Tonic 展示 gRPC 客户端/服务器
  • 如何将 Tonic 与 Axum 整合在一起

让我们开始吧!

Tower 总览

什么是 Tower

我们旅图的第一站是Tower crate, 引用文档中的总结:

Tower 提供了一个简单的核心抽象,即 Service 特性,它表示一个接受请求并返回响应或错误的异步函数。这种抽象可用于对客户端和服务器进行建模。

这听起来相当简单。假如用 Haskell 语法表达它,可能会是 Request -> IO Response,利用 IO 既能处理错误又能处理异步 I/O 的特点。但 Service trait 必然比这函数签名更复杂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pub trait Service<Request> {
type Response;
type Error;

// This is what it says in the generated docs
type Future: Future;

// But this more informative piece is in the actual source code
type Future: Future<Output = Result<Self::Response, Self::Error>>;

fn poll_ready(
&mut self,
cx: &mut Context<'_>
) -> Poll<Result<(), Self::Error>>;
fn call(&mut self, req: Request) -> Self::Future;
}

Service 是一个 trait, 其类型参数是它可以处理的请求类型. 在 Tower 中并没有明确限制请求的类型必须是 HTTP, 因此它可以处理许多不同的 HTTP 请求. 就如同使用了 Tower 的 Hpyer 库中, 就存在至少两种类型的请求.

不过先不管那些, 在这里有两个相关联的类型是直接明了的: Response和Error. 将这两个类型与特定的 Request 组合,我们就获得了处理请求所需的所有信息.

但这些并不是 Rust 所关系的全部. 为了能够提供异步调用, 我们需要提供一个 Future. 编译器

Author: Sean
Link: https://blog.whileaway.io/posts/eef9775e/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.