宣布tower-http:HTTP特定中间件和实用程序的集合
用Tower的 service trait 构建的HTTP特定中间件和实用程序的集合
今天我很高兴地宣布tower-http,它是一个用Tower的 service trait 构建的HTTP特定中间件和实用程序的集合。
Tower本身包含的中间件都是与协议无关的。例如,它的超时中间件与任何服务实现兼容,无论它使用哪种协议。这很好,因为它意味着中间件更可重用,但也意味着你不能使用协议的特定功能。在HTTP的情况下,这意味着Tower中的中间件不知道状态码、头信息或其他HTTP的特定功能。
另一方面,tower-http
包含了针对HTTP的中间件。它使用 http
和 http-body
crate,这意味着它与任何使用这些板块的板块兼容,例如 hyper、tonic 和 warp。
tower-http 的目标是提供一套丰富的中间件来解决构建 HTTP 客户端和服务器时的常见问题。一些亮点是:
-
追踪:轻松地在你的应用程序中添加高级别的 tracing/logging。支持通过状态代码以及 gRPC 特定的头信息来确定成功或失败。有很好的默认值,但也支持深度定制。
-
压缩和解压:自动压缩或解压响应体。这与使用
ServeDir
的静态文件的服务非常吻合。 -
FollowRedirect:自动跟踪重定向响应。
还有一些小工具,如设置请求和响应头,从日志中隐藏敏感头,授权等。
用tower-http中的东西构建一个小服务器看起来像这样:
use tower_http::{
compression::CompressionLayer,
auth::RequireAuthorizationLayer,
trace::TraceLayer,
};
use tower::{ServiceBuilder, make::Shared};
use http::{Request, Response};
use hyper::{Body, Error, server::Server};
use std::net::SocketAddr;
// Our request handler. This is where we would implement the application logic
// for responding to HTTP requests...
async fn handler(request: Request<Body>) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::from("Hello, World!")))
}
#[tokio::main]
async fn main() {
// Use `tower`'s `ServiceBuilder` API to build a stack of middleware
// wrapping our request handler.
let service = ServiceBuilder::new()
// High level tracing of requests and responses.
.layer(TraceLayer::new_for_http())
// Compress responses.
.layer(CompressionLayer::new())
// Authorize requests using a token.
.layer(RequireAuthorizationLayer::bearer("tower-is-cool"))
// Wrap a `Service` in our middleware stack.
.service_fn(handler);
// And run our service using `hyper`.
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
Server::bind(&addr)
.serve(Shared::new(service))
.await
.expect("server error");
}
而建立一个看起来是这样的客户:
use tower_http::{
decompression::DecompressionLayer,
set_header::SetRequestHeaderLayer,
};
use tower::ServiceBuilder;
use hyper::Body;
use http::{Request, Response, HeaderValue, header::USER_AGENT};
let client = ServiceBuilder::new()
// Log failed requests
.layer(
TraceLayer::new_for_http()
.on_request(())
.on_response(())
.on_body_chunk(())
.on_eos(())
// leave the `on_failure` callback as the default
)
// Set a `User-Agent` header on all requests
.layer(SetRequestHeaderLayer::<_, Body>::overriding(
USER_AGENT,
HeaderValue::from_static("my-app")
))
// Decompress response bodies
.layer(DecompressionLayer::new())
// Wrap a `hyper::Client` in our middleware stack
.service(hyper::Client::new());
我们在文档中投入了大量的精力,确保每件事都有易于理解的例子。我们还建立了两个例子,一个用warp,另一个用tonic,向你展示如何把所有东西放在一起。
我们非常欢迎你的贡献,如果你有问题,你可以在Tokio Discord服务器找到我们。