宣布Tonic 0.5版本

Tonic是Rust的gRPC原生实现。0.5是一个重要的版本

我们很高兴地宣布 Tonic 的0.5版本,它是 Rust 的原生 gRPC 实现。0.5是一个重要的版本,已经酝酿了一段时间。

一些关键的新功能是:

gRPC-Web

gRPC-Web 是一个协议,允许客户端通过 HTTP/1.1 连接到 gRPC 服务,而不是通常的HTTP/2。gRPC-Web 的一个常见用例是在浏览器中运行的JavaScript客户端。以前,这需要使用一个代理来将 HTTP/2 请求翻译成 HTTP/1.1。

然而,新的 crate tonic-web 允许普通的 Tonic 服务器接受 gRPC-Web 请求,而不需要外部代理。

启用gRPC-Web支持很简单:

use tonic::transport::Server;
// code generated by tonic-build
use hello_world::greeter_server::{GreeterServer, Greeter};

struct MyGreeter;

#[tonic::async_trait]
impl Greeter for MyGreeter {
    // ...
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "0.0.0.0:3000".parse().unwrap();

    let greeter = GreeterServer::new(MyGreeter);

    // enable grpc-web support for our `greeter` service
    let service = tonic_web::enable(greeter);

    Server::builder()
        // by default, tonic servers only accept http2 requests
        // so we have to enable receiving http1 as well
        .accept_http1(true)
        .add_service(service)
        .serve(addr)
        .await?;

    Ok(())
}

更多细节请见tonic-web crate。

压缩

Tonic现在可以透明地压缩和解压请求、响应和数据流。

在客户端上启用压缩功能是这样做的:

let client = GreeterClient::new(channel)
    // compress requests
    .send_gzip()
    /// accept compressed responses
    .accept_gzip();

而在服务器上:

let service = GreeterServer::new(greeter)
    // accept compressed requests
    .accept_gzip()
    // compress responses, if supported by the client
    .send_gzip();

注意这需要在 Tonictonic-build 上启用 compression 功能。更多细节请参见文档。

改进的Tower集成

Tonic 一直支持通过 Tower 的 Service trait 来扩展客户端和服务器,但在0.5版本中,新的 Server::layer 方法使其更加简单。例如,我们可以通过使用来自 tower-http 的中间件来为一个服务添加追踪和授权:

use tonic::transport::Server;
use tower_http::{
    auth::RequireAuthorizationLayer,
    trace::TraceLayer,
};

// The stack of middleware our service will be wrapped in
let layer = tower::ServiceBuilder::new()
    // High level tracing of requests and responses
    .layer(TraceLayer::new_for_grpc())
    // Authorize all requests using a token
    .layer(RequireAuthorizationLayer::bearer("my-secret-token"))
    // Convert our `ServiceBuilder` into a `tower::Layer`
    .into_inner();

Server::builder()
    // Apply our middleware stack to the server
    .layer(layer)
    .add_service(GreeterServer::new(MyGreeter)
    .serve(addr)
    .await?;

更灵活的拦截器

拦截器是轻量级的中间件,除其他外,可以用来修改传入请求的元数据,也可以选择用状态拒绝它们。

然而,Tonic对拦截器的支持一直是相当有限的。例如,你不能结合多个拦截器,而必须使用Tower的 service 抽象,它更强大,但也需要更多的代码来设置。

在Tonic 0.5中,我们有一个新的拦截器API,和以前一样容易使用,但现在内部使用Tower。这意味着拦截器可以像其他Tower中间件一样被应用。例如,在一个客户端添加多个拦截器,现在可以用:

use tonic::{
  Request, Status,
  service::interceptor_fn,
  transport::Endpoint
};

fn intercept_one(req: Request<()>) -> Result<Request<()>, Status> {
    // ...
}

fn intercept_two(req: Request<()>) -> Result<Request<()>, Status> {
    // ...
}

let channel = Endpoint::from_static("http://[::1]:50051").connect_lazy()?;

let intercepted_channel = tower::ServiceBuilder::new()
    .layer(interceptor_fn(intercept_one))
    .layer(interceptor_fn(intercept_two))
    .service(channel);

let client = GreeterClient::new(intercepted_channel);

0.5包括许多其他较小的功能和改进。更新日志里有所有的细节。

如同以往,如果你有问题,你可以在Tokio Discord服务器的#tonic找到我们。

内容出处: https://tokio.rs/blog/2021-07-tonic-0-5