为何对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
相关产品推荐
相关产品推荐

