Actix Web中间件编译报错:类型不匹配与值已移动问题
Actix Web中间件编译错误解决方法
错误原因与解决方案
1. E0308 类型不匹配(预期()却找到Result<ServiceResponse<B>, _>)
问题出在call方法的返回值类型不符合要求:
call方法必须返回Pin<Box<dyn Future<Output = Result<ServiceResponse<B>, Error>>>>类型,而非直接返回Result。- 之前的代码可能在条件分支里直接返回了错误响应的
Result,没有包裹成Future,也未用return终止分支,导致代码路径类型冲突。
2. E0382 值已移动(req在移动后被使用)
ServiceRequest是所有权类型:
- 调用
req.into_response(resp)会消耗req的所有权,如果之后代码还尝试使用req(比如修改头、传递给下一个服务),就会触发该错误。 - 修正思路是先通过引用完成条件检查,仅在确定返回错误时才消耗
req,其余场景使用可变引用修改请求头后正常传递。
修正后的完整代码
中间件实现
use actix_web::{dev::{Service, ServiceRequest, ServiceResponse, Transform}, Error, HttpResponse}; use futures::future::ok; use std::{ future::{Future, Ready}, pin::Pin, task::{Context, Poll}, }; // 中间件结构体 pub struct HeaderMiddleware; impl<S, B> Transform<S, ServiceRequest> for HeaderMiddleware where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse<B>; type Error = Error; type InitError = (); type Transform = HeaderMiddlewareService<S>; type Future = Ready<Result<Self::Transform, Self::InitError>>; fn new_transform(&self, service: S) -> Self::Future { ok(HeaderMiddlewareService { service }) } } pub struct HeaderMiddlewareService<S> { service: S, } impl<S, B> Service<ServiceRequest> for HeaderMiddlewareService<S> where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse<B>; type Error = Error; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>; fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.service.poll_ready(cx) } fn call(&self, mut req: ServiceRequest) -> Self::Future { // 1. 引用方式检查请求条件,不移动req所有权 let is_valid = req.headers() .get("X-Valid-Header") .and_then(|h| h.to_str().ok()) .map(|val| val == "allowed") .unwrap_or(false); if !is_valid { // 仅在返回错误时消耗req,包装成Future返回 let err_resp = HttpResponse::Forbidden() .body("Request fails validation"); return Box::pin(async { Ok(req.into_response(err_resp)) }); } // 2. 用可变引用修改请求头,不转移所有权 req.headers_mut().insert( "X-Middleware-Processed", actix_web::http::HeaderValue::from_static("true"), ); // 3. 传递请求给下一个服务 let next_fut = self.service.call(req); Box::pin(async move { let res = next_fut.await?; Ok(res) }) } }
主程序
use actix_web::{web, App, HttpServer, Responder}; async fn index() -> impl Responder { "Hello World!" } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .wrap(HeaderMiddleware) .route("/", web::get().to(index)) }) .bind(("127.0.0.1", 8080))? .run() .await }
内容的提问来源于stack exchange,提问作者user63898
相关产品推荐
相关产品推荐

