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

为何对actix-web应用做条件式CORS包装时出现类型不匹配错误?

Actix-web条件式CORS包装类型不匹配错误原因分析

问题场景

尝试给actix-web应用添加条件式CORS中间件(通过配置决定是否启用)时,出现类型不匹配错误,相关代码如下:

use actix_cors::Cors;
use actix_web::{http::header, App, HttpServer};
use std::{net::SocketAddr, sync::Arc};

use common::config::Config;

pub async fn start(config: Arc<Config>) -> std::io::Result<()> {
    let config_app = Arc::clone(&config);

    let server = HttpServer::new(move || {
        let mut app = App::new();

        if config_app.cors.enabled {
            app = app.wrap( // 错误发生在此处
                Cors::default()
                    .allowed_origin("http://localhost:8080")
                    .allowed_methods(vec!["GET", "POST"])
                    .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
                    .allowed_header(header::CONTENT_TYPE)
                    .supports_credentials()
                    .max_age(3600),
            )
        }

        app
    });

    let addr = SocketAddr::from(([127, 0, 0, 1], config.port));

    server.bind(addr)?.run().await
}

报错信息

mismatched types
expected struct `actix_web::App<actix_web::app_service::AppEntry>`
   found struct `actix_web::App<impl actix_web::dev::ServiceFactory<actix_web::dev::ServiceRequest, Config = (), Response = actix_web::dev::ServiceResponse<actix_web::body::EitherBody<actix_web::body::BoxBody>>, Error = actix_web::Error, InitError = ()>>` rustc E0308

app.rs(355, 9): the found opaque type

server.rs(13, 23): expected due to this value

错误原因

Rust的类型系统要求同一变量的所有分支必须返回完全一致的类型:

  • 执行app.wrap(Cors...)时,返回的App实例泛型参数是一个匿名的impl ServiceFactory类型(由Cors中间件注入的服务工厂类型)
  • 不执行wrap分支时,初始的App::new()返回的是App<AppEntry>类型
  • 两个分支的App类型不匹配,编译器无法统一类型,因此抛出E0308类型不匹配错误

解决方法

方法1:提前分支创建App

直接在条件分支中分别创建带Cors和不带Cors的App,确保两个分支返回的类型一致:

let server = HttpServer::new(move || {
    if config_app.cors.enabled {
        App::new()
            .wrap(
                Cors::default()
                    .allowed_origin("http://localhost:8080")
                    .allowed_methods(vec!["GET", "POST"])
                    .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
                    .allowed_header(header::CONTENT_TYPE)
                    .supports_credentials()
                    .max_age(3600),
            )
    } else {
        App::new()
    }
});

方法2:用boxed()统一类型

通过boxed()方法将两个分支的App转换为 trait 对象类型,消除类型差异:

use actix_web::dev::ServiceFactory;

// ...

let server = HttpServer::new(move || {
    let app = if config_app.cors.enabled {
        App::new()
            .wrap(
                Cors::default()
                    .allowed_origin("http://localhost:8080")
                    .allowed_methods(vec!["GET", "POST"])
                    .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
                    .allowed_header(header::CONTENT_TYPE)
                    .supports_credentials()
                    .max_age(3600),
            )
            .boxed()
    } else {
        App::new().boxed()
    };

    app
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 12:15:41