fnhandle_request(request: HttpRequest) -> HttpResponse { if request.path() == "/" { HttpResponse::ok("Hello, World!") } else { HttpResponse::not_found() } } // Run the server and handle requests using our `handle_request` function server.run(handle_request).await?;
implServer { asyncfnrun<F, Fut>(self, handler: F) ->Result<(), Error> where // `handler` now returns a generic type `Fut`... F: Fn(HttpRequest) -> Fut, // ...which is a `Future` whose `Output` is an `HttpResponse` Fut: Future<Output = HttpResponse>, { letlistener = TcpListener::bind(self.addr).await?;
task::spawn(asyncmove { // Await the future returned by `handler` letresponse = handler(request).await; write_http_response(connection, response).await?; }); } } } // Now an async function asyncfnhandle_request(request: HttpRequest) -> HttpResponse { if request.path() == "/" { HttpResponse::ok("Hello, World!") } elseif request.path() == "/important-data" { // We can now do async stuff in here letsome_data = fetch_data_from_database().await; make_response(some_data) } else { HttpResponse::not_found() } } // Running the server is the same server.run(handle_request).await?;
task::spawn(asyncmove { // Pattern match on the result of the response future matchhandler(request).await { Ok(response) => write_http_response(connection, response).await?, Err(error) => handle_error_somehow(error, connection), } }); } } }
implHandlerforRequestHandler { // We use `Pin<Box<...>>` here for simplicity, but could also define our // own `Future` type to avoid the overhead typeFuture = Pin<Box<dyn Future<Output = Result<HttpResponse, Error>>>>;
fncall(&mutself, request: HttpRequest) ->Self::Future { Box::pin(asyncmove { // same implementation as we had before if request.path() == "/" { Ok(HttpResponse::ok("Hello, World!")) } elseif request.path() == "/important-data" { letsome_data = fetch_data_from_database().await?; Ok(make_response(some_data)) } else { Ok(HttpResponse::not_found()) } }) } }
对于超时,可以像下面这样定义一个通用的Timeout结构:
1 2 3 4 5
structTimeout<T> { // T will be some type that implements `Handler` inner_handler: T, duration: Duration, }
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> src/lib.rs:145:29 | 144 | fncall(&mutself, request: HttpRequest) ->Self::Future { | --------- this data with an anonymous lifetime `'_`... 145 | Box::pin(asyncmove { | _____________________________^ 146 | | letresult = tokio::time::timeout( 147 | | self.duration, 148 | | self.inner_handler.call(request), ... | 155 | | } 156 | | }) | |_________^ ...is captured here, requiring it to live as long as `'static`
// Error should also be an associated type. No reason for that to be a // hardcoded type typeError;
// Our future type from before, but now it's output must use // the associated `Response` and `Error` types typeFuture: Future<Output = Result<Self::Response, Self::Error>>;
// `call` is unchanged, but note that `Request` here is our generic // `Request` type parameter and not the `HttpRequest` type we've used // until now fncall(&mutself, request: Request) ->Self::Future; }
// `Timeout` accepts any request of type `R` as long as `T` // accepts the same type of request impl<R, T> Handler<R> forTimeout<T> where // The actual type of request must not contain // references. The compiler would tell us to add // this if we didn't R: 'static, // `T` must accept requests of type `R` T: Handler<R> + Clone + 'static, // We must be able to convert an `Elapsed` into // `T`'s error type T::Error: From<tokio::time::error::Elapsed>, { // Our response type is the same as `T`'s, since we // don't have to modify it typeResponse = T::Response;
// Error type is also the same typeError = T::Error;
// Future must output a `Result` with the correct types typeFuture = Pin<Box<dyn Future<Output = Result<T::Response, T::Error>>>>;
fncall(&mutself, request: R) ->Self::Future { letmut this = self.clone();
impl<R, T> Service<R> forConcurrencyLimit<T> { fncall(&mutself, request: R) ->Self::Future { // 1. Check a counter for the number of requests currently being // processed. // 2. If there is capacity left send the request to `T` // and increment the counter. // 3. If not somehow wait until capacity becomes available. // 4. When the response has been produced, decrement the counter. } }