You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hyper 0.14 Service实现中使用自有方法的生命周期错误问题

Hyper 0.14 Service结构体异步方法生命周期错误解决

问题背景

我希望在Hyper 0.14的Service结构体实现中使用自有结构体的方法,通过结构体简化请求数据访问,而非将数据传递给函数。Hyper文档说明:“Trait hyper::service::Service是从Request到Response的异步函数,是Tower的核心抽象之一,便于模块化编写网络应用。”但调用结构体异步方法时出现如下错误:

error: lifetime may not live long enough
  --> examples/service_struct_impl.rs:36:9
   |
35 |     fn call(&mut self, req: Request<Body>) -> Self::Future {
   |             - let's call the lifetime of this reference `'1`
36 |         Box::pin(self.start_process(req))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`

原代码:

use hyper::service::Service;
use hyper::{Body, Request, Response, Server};
use hyper::StatusCode;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

type Counter = i32;
type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let addr = ([127, 0, 0, 1], 3000).into();

    let server = Server::bind(&addr).serve(MakeSvc { counter: 81818 });
    println!("Listening on http://{}", addr);

    server.await?;
    Ok(())
}

struct Svc {
    counter: Counter,
}

impl Service<Request<Body>> for Svc {
    type Response = Response<Body>;
    type Error = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

    fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        Box::pin(self.start_process(req))
    }
}

impl Svc {
    async fn start_process(
        &mut self,
        req: Request<Body>
    ) -> Result<Response<Body>, GenericError> {
        Ok(Response::builder()
            .status(StatusCode::INTERNAL_SERVER_ERROR)
            .body(Body::from(format!("Counter is: {}", self.counter)))?)
    }
}

错误原因

报错核心是:call方法返回的Future捕获了&mut self的引用,但你定义的Self::Future类型默认要求Future具备'static生命周期(可存活至程序结束),而&mut self的生命周期仅局限于call方法调用期间,无法满足'static要求,导致编译器抛出生命周期不匹配错误。

解决方案

方案一:使用共享状态(推荐)

通过Arc<Mutex<>>包装结构体中的共享状态,让异步方法通过克隆Arc获取状态访问权,避免Future持有&mut self的引用。这种方式适用于需要复用Service实例、处理多个请求的场景。

修改后的完整代码:

use hyper::service::{Service, MakeService};
use hyper::{Body, Request, Response, Server};
use hyper::StatusCode;
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};

type Counter = i32;
type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let addr = ([127, 0, 0, 1], 3000).into();
    // 用Arc<Mutex>包装共享计数器
    let counter = Arc::new(Mutex::new(81818));
    let server = Server::bind(&addr).serve(MakeSvc { counter });
    println!("Listening on http://{}", addr);

    server.await?;
    Ok(())
}

// MakeSvc负责为每个连接/请求创建Service实例
struct MakeSvc {
    counter: Arc<Mutex<Counter>>,
}

impl MakeService<hyper::server::conn::AddrStream> for MakeSvc {
    type Response = Response<Body>;
    type Error = GenericError;
    type Service = Svc;
    type MakeError = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::MakeError>> + Send>>;

    fn make_service(&mut self, _conn: &hyper::server::conn::AddrStream) -> Self::Future {
        // 克隆Arc,传递给新的Svc实例
        let counter = self.counter.clone();
        Box::pin(async move { Ok(Svc { counter }) })
    }
}

struct Svc {
    counter: Arc<Mutex<Counter>>,
}

impl Service<Request<Body>> for Svc {
    type Response = Response<Body>;
    type Error = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

    fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        // 克隆Arc,让Future持有所有权
        let counter = self.counter.clone();
        Box::pin(async move {
            // 锁定Mutex访问并修改计数器
            let mut count = counter.lock().map_err(|e| format!("Mutex lock failed: {}", e))?;
            *count += 1;
            Ok(Response::builder()
                .status(StatusCode::OK)
                .body(Body::from(format!("Counter is: {}", *count)))?)
        })
    }
}

方案二:消耗Service实例(仅适用于一次性场景)

如果你的Service实例不需要复用,仅处理单个请求,可以修改call方法的签名,让它消耗self的所有权,这样Future可以持有整个结构体,无需引用:

// 修改Svc的Service实现中的call方法
impl Service<Request<Body>> for Svc {
    type Response = Response<Body>;
    type Error = GenericError;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

    fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    // 将&mut self改为self,消耗实例所有权
    fn call(self, req: Request<Body>) -> Self::Future {
        Box::pin(async move {
            Ok(Response::builder()
                .status(StatusCode::OK)
                .body(Body::from(format!("Counter is: {}", self.counter)))?)
        })
    }
}

注意:这种方式下每个Svc实例只能处理一个请求,不适用于需要持续处理请求的服务场景。


内容的提问来源于stack exchange,提问作者Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:12:36