宣布tower-http:HTTP特定中间件和实用程序的集合

用Tower的 service trait 构建的HTTP特定中间件和实用程序的集合

今天我很高兴地宣布tower-http,它是一个用Tower的 service trait 构建的HTTP特定中间件和实用程序的集合。

Tower本身包含的中间件都是与协议无关的。例如,它的超时中间件与任何服务实现兼容,无论它使用哪种协议。这很好,因为它意味着中间件更可重用,但也意味着你不能使用协议的特定功能。在HTTP的情况下,这意味着Tower中的中间件不知道状态码、头信息或其他HTTP的特定功能。

另一方面,tower-http 包含了针对HTTP的中间件。它使用 httphttp-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服务器找到我们。

内容出处: https://tokio.rs/blog/2021-05-announcing-tower-http