发布 Tonic 0.5
2021年7月9日
我们很高兴地宣布 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();
请注意,这需要在 Tonic 和 tonic-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?;
更灵活的拦截器
拦截器是轻量级中间件,除其他外,可用于修改传入请求的元数据,并可以选择使用 status 拒绝它们。
然而,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
频道中找到我们。