MST

星途 面试题库

面试题:Rust Web服务器的错误处理与中间件应用

基于`actix - web`框架搭建的Rust Web服务器,当处理请求时遇到错误(例如数据库查询失败、参数解析错误等),如何进行优雅的错误处理并返回合适的HTTP状态码和错误信息?同时,请实现一个中间件,用于记录每个请求的访问时间。给出关键代码逻辑和实现思路。
34.9万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

错误处理与返回合适HTTP状态码和错误信息

  1. 定义错误类型
    use actix_web::http::StatusCode;
    use thiserror::Error;
    
    #[derive(Error, Debug)]
    pub enum AppError {
        #[error("Database query failed")]
        DatabaseError,
        #[error("Parameter parsing error")]
        ParameterError,
    }
    
    impl actix_web::ResponseError for AppError {
        fn status_code(&self) -> StatusCode {
            match self {
                AppError::DatabaseError => StatusCode::INTERNAL_SERVER_ERROR,
                AppError::ParameterError => StatusCode::BAD_REQUEST,
            }
        }
    
        fn error_response(&self) -> actix_web::HttpResponse {
            actix_web::HttpResponse::build(self.status_code())
               .content_type("application/json")
               .body(format!("{{\"error\":\"{}\"}}", self))
        }
    }
    
  2. 在处理函数中返回错误
    use actix_web::{web, HttpResponse};
    
    async fn index() -> Result<HttpResponse, AppError> {
        // 模拟数据库查询失败
        if rand::random::<bool>() {
            Err(AppError::DatabaseError)
        } else {
            Ok(HttpResponse::Ok().body("Success"))
        }
    }
    

实现记录请求访问时间的中间件

  1. 中间件逻辑
    use actix_web::{dev::Service, dev::ServiceRequest, dev::ServiceResponse, Error, HttpResponse};
    use std::time::{SystemTime, UNIX_EPOCH};
    
    struct AccessTimeLogger;
    
    impl<S, B> Service<ServiceRequest> for AccessTimeLogger
    where
        S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
        S::Future: 'static,
        B: 'static,
    {
        type Response = ServiceResponse<B>;
        type Error = Error;
        type Future = Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>>>;
    
        fn poll_ready(
            &mut self,
            _cx: &mut std::task::Context<'_>,
        ) -> std::task::Poll<Result<(), Self::Error>> {
            std::task::Poll::Ready(Ok(()))
        }
    
        fn call(&mut self, req: ServiceRequest) -> Self::Future {
            let start = SystemTime::now();
            let svc = req.get_ref();
            Box::new(async move {
                let res = svc.call(req).await?;
                let elapsed = start.elapsed().unwrap().as_millis();
                println!("Request took {} ms", elapsed);
                Ok(res)
            })
        }
    }
    
  2. 应用中间件
    use actix_web::App;
    
    fn main() {
        let app = App::new()
           .wrap(AccessTimeLogger)
           .service(index);
        // 启动服务器相关代码
    }
    

实现思路总结

  1. 错误处理
    • 使用thiserror库定义自定义错误类型AppError,针对不同的错误情况(如数据库查询失败、参数解析错误)进行枚举。
    • AppError实现actix_web::ResponseError trait,在其中定义合适的HTTP状态码和错误响应格式。
    • 在处理函数中,根据业务逻辑返回Result<HttpResponse, AppError>,当遇到错误时返回Err(AppError::具体错误类型)
  2. 中间件
    • 定义一个结构体AccessTimeLogger,实现Service trait。
    • call方法中记录请求开始时间,调用下一个服务获取响应,计算请求处理时间并打印日志。
    • 通过App::wrap方法将中间件应用到actix - web应用中。