Rust Web入门(四):错误处理

news/2024/4/18 18:35:05/文章来源:https://blog.csdn.net/weixin_46463785/article/details/129223961

本教程笔记来自 杨旭老师的 rust web 全栈教程,链接如下:

https://www.bilibili.com/video/BV1RP4y1G7KF?p=1&vd_source=8595fbbf160cc11a0cc07cadacf22951

学习 Rust Web 需要学习 rust 的前置知识可以学习杨旭老师的另一门教程

https://www.bilibili.com/video/BV1hp4y1k7SV/?spm_id_from=333.999.0.0&vd_source=8595fbbf160cc11a0cc07cadacf22951

今天来入门基于 rust 的 web 怎么样处理错误:

Actix错误处理机制

actix 定义了一个通用的错误类型, actix_web::error::Error , 任何实现了 Error Trait 的类型,都可以通过 ? 运算转化为 Actix 的Error类型

如果在实现了 ResponseError trait 的 Result 中返回 Error,则 actix-web 会将该错误呈现为一个 HTTP 响应,并使用相应的状态码,能实现这个功能的包含了对常见的错误,如 IO错误,Serde 错误,Web 错误等

自定义错误处理器

在内置实现不可用的时候,可以自定义错误到 HTTP Respone。实现 ResponseError 来现实返回一个 HTTP 请求,具体如下:

我们首先自定义一个error.rs 来自定义我们的错误类型,我们创建一个枚举来列举我们可能出现的错误,在定义一个结构来存储我们返回给用户的响应的内容:

use actix_web::{error, http::StatusCode, HttpResponse, Result};
use serde::Serialize;
use sqlx::error::Error as SQLxError;
use std::fmt;use actix_web::{error, http::StatusCode, HttpResponse, Result};
use serde::Serialize;
use sqlx::error::Error as SQLxError;
use std::fmt;#[derive(Debug, Serialize)]
pub enum MyError {DBError(String),ActixError(String),#[allow(dead_code)]NotFound(String),
}#[derive(Debug, Serialize)]
pub struct MyErrorResponse {error_message: String,
}

之后我们为 MyError 实现 ResponseError trait ,它包含一些方法,可以在错误发生的时候,将错误转化为一个 Http Respone 返回给用户:

error_response 返回一个给用户的响应信息,而 status_code 返回一个对应的状态码,通过传入一个 error,可以得到返回给用户的响应的具体内容,从而实现错误到 Http Respone 的转换:

impl MyError {fn error_response(&self) -> String {match self {MyError::DBError(msg) => {println!("Database error occurred: {:?}", msg);"Database error".into()}MyError::ActixError(msg) => {println!("Server error occurred: {:?}", msg);"Internal server error".into()}MyError::NotFound(msg) => {println!("Not found error occurred: {:?}", msg);msg.into()}}}
}impl error::ResponseError for MyError {fn status_code(&self) -> StatusCode {match self {MyError::DBError(_msg) | MyError::ActixError(_msg) => StatusCode::INTERNAL_SERVER_ERROR,MyError::NotFound(_msg) => StatusCode::NOT_FOUND,}}fn error_response(&self) -> HttpResponse {HttpResponse::build(self.status_code()).json(MyErrorResponse {error_message: self.error_response(),})}
}

因为 error::ResponseError 这个接口还需要我们实现 Debug 和 Display ,所以我们加上 Display 的实现:

impl fmt::Display for MyError {fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {write!(f, "{}", self)}
}

最后,我们需要将原生的错误类型接入到我们的错误处理中,我们为原生的错误类型实现 From ,当发生原生错误的时候,它就会转化为我们枚举里定义的错误,然后根据我们的代码返回:

impl From<actix_web::error::Error> for MyError {fn from(err: actix_web::error::Error) -> Self {MyError::ActixError(err.to_string())}
}impl From<SQLxError> for MyError {fn from(err: SQLxError) -> Self {MyError::DBError(err.to_string())}
}

为项目添加错误处理

现在我们有了一个错误处理的类,我们需要把它用在我们的代码中,因为我们之前说过,任何实现了 Error Trait 的类型,都可以通过 ? 运算转化为 Actix 的 Error 类型,所以我们将之前所有的 unwarp() 替换成 ? 运算即可

同时,我们的返回值就需要改成 Result 类型,成功时返回一个 Ok 包裹数据,失败的时候则通过 ? 运算返回一个 error 类型,而数据库的 error 已经包装进了我们的 MyError 中,所以会自动转化为一个 MyError :

use super::error::MyError;
use crate::models::*;
use sqlx::mysql::MySqlPool;pub async fn get_courses_for_teacher_db(pool: &MySqlPool,teacher_id: i32,
) -> Result<Vec<Course>, MyError> {let rows = sqlx::query!("SELECT id, teacher_id, name, timeFROM courseWHERE teacher_id = ?",teacher_id).fetch_all(pool).await?;let courses: Vec<Course> = rows.iter().map(|r| Course {id: Some(r.id),teacher_id: r.teacher_id,name: r.name.clone(),time: Some(r.time.unwrap()),}).collect();match courses.len() {0 => Err(MyError::NotFound("Course not found for teacher".into())),_ => Ok(courses),}
}pub async fn get_course_details_db(pool: &MySqlPool,teacher_id: i32,course_id: i32,
) -> Result<Course, MyError> {let row = sqlx::query!("SELECT id, teacher_id, name, timeFROM courseWHERE teacher_id = ? and id = ?",teacher_id,course_id).fetch_one(pool).await;if let Ok(row) = row {Ok(Course {id: Some(row.id),teacher_id: row.teacher_id,name: row.name.clone(),time: Some(row.time.unwrap()),})} else {Err(MyError::NotFound("Course didn't founded".into()))}
}pub async fn post_new_course_db(pool: &MySqlPool, new_course: Course) -> Result<Course, MyError> {let data = sqlx::query!("INSERT INTO course ( teacher_id, name)VALUES ( ?, ?)",new_course.teacher_id,new_course.name,).execute(pool).await?;let row = sqlx::query!("SELECT id, teacher_id, name, timeFROM courseWHERE id = ?",data.last_insert_id()).fetch_one(pool).await?;Ok(Course {id: Some(row.id),teacher_id: row.teacher_id,name: row.name.clone(),time: Some(row.time.unwrap()),})
}

因为我们的数据库方法返回值改变了,所以我们的 handlers 也需要更改,我们使用 map 来处理结果:如果调用数据库成功,收到 OK, map 会将返回值包装成一个 HTTP 响应,如果过程中发生错误,map 会返回一个 error,因为我们已经把相关错误接入了 MyError 这个类型,那么发生的错误就会变成 MyError ,而它实现了 ResponseError 所以会自动转化为一个 HTTP 请求返回给用户:

use super::db_access::*;
use super::error::MyError;
use super::state::AppState;
use actix_web::{web, HttpResponse};pub async fn health_check_handler(app_state: web::Data<AppState>) -> HttpResponse {println!("incoming for health check");let health_check_response = &app_state.health_check_response;let mut visit_count = app_state.visit_count.lock().unwrap();let response = format!("{} {} times", health_check_response, visit_count);*visit_count += 1;HttpResponse::Ok().json(&response)
}use super::models::Course;
pub async fn new_course(new_course: web::Json<Course>,app_state: web::Data<AppState>,
) -> Result<HttpResponse, MyError> {post_new_course_db(&app_state.db, new_course.into()).await.map(|course| HttpResponse::Ok().json(course))
}pub async fn get_courses_for_teacher(app_state: web::Data<AppState>,params: web::Path<(usize,)>,
) -> Result<HttpResponse, MyError> {let teacher_id = i32::try_from(params.0).unwrap();get_courses_for_teacher_db(&app_state.db, teacher_id).await.map(|courses| HttpResponse::Ok().json(courses))
}pub async fn get_course_detail(app_state: web::Data<AppState>,params: web::Path<(usize, usize)>,
) -> Result<HttpResponse, MyError> {let teacher_id = i32::try_from(params.0).unwrap();let course_id = i32::try_from(params.1).unwrap();get_course_details_db(&app_state.db, teacher_id, course_id).await.map(|course| HttpResponse::Ok().json(course))
}

最后我们运行测试用例,如果允许均通过,说明我们的错误处理编写成功。

最后我们启动我们的服务器,然后尝试访问一个不存在 id ,比如 http://localhost:3000/courses/1111 ,如果返给你如下的响应,说明你的项目编写成功了:

{"error_message": "Course not found for teacher"
}

说明

本教程只是作者的学习笔记,帮助理解和记忆 RUST 开发,课程全部来源是 B站 杨旭老师的教程:

https://www.bilibili.com/video/BV1RP4y1G7KF?p=1&vd_source=8595fbbf160cc11a0cc07cadacf22951

教学 demo 可以查看大佬的 git:

https://github.com/FrancisYLfan/rust_web_server_from_yang

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_74226.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAPI SDK组件介绍

背景 公司成立以来&#xff0c;积累了数以万计的可复用接口。上层的SaaS业务&#xff0c;原则上要复用这些接口开发自己的业务&#xff0c;为了屏蔽调用接口的复杂性&#xff0c;基础服务开发了apisdk组件&#xff0c;定义了一套声明OpenAPI的注解、注解解析器&#xff0c;实例…

scrapy下载图片

&#x1f431; 个人主页&#xff1a;莎萌玩家&#x1f64b;‍♂️ 作者简介&#xff1a;全栈领域新星创作者、专注于全栈各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01;&#x1f4ab;系列专栏&#xff1a;网络爬虫、WEB全栈开发&#x1f4e2; 资料…

你应该知道的ChatGPT提示语

ChatGPT 自上线以来&#xff0c;凭借其优异的自然语言理解和输出能力&#xff0c;仅花 5天就成为了活跃用户过百万的现象级产品。而上一个现象级产品 instagram 花了 2 个半月。到目前为止 ChatGPT 在全球累计用户数量已经过亿&#xff0c;相信现在也有很多人在跟 ChatGPT 聊过…

OKR 与 KPI有何异同?各部门OKR实例【小bu】

OKR 与 KPI&#xff0c;如何本土化是关键 近期公司计划对去年实施的绩效考核方案进行优化&#xff0c;公司以往采用 KPI 绩效考核方式&#xff0c;产生了一些争议。一方面&#xff0c;执行期间部分部门一度忽略指标设置的真实目的&#xff0c;导致出现短视思维和行为&#xff1…

TCP协议原理二

文章目录四、滑动窗口二、流量窗口三、拥塞控制四、滑动窗口 前面我们学习了 确认应答&#xff0c;超时重传&#xff0c;连接管理&#xff0c;这些机制都为我们TCP的可靠性提供了保证&#xff0c;当然在保证TCP的可靠性的同时&#xff0c;传输效率也受到了一定的影响&#xff…

05 DC-AC逆变器(DCAC Converter / Inverter)简介

文章目录0、概述逆变原理方波变换阶梯波变换斩控调制方式逆变器分类逆变器波形指标1、方波变换器A 单相单相全桥对称单脉冲调制移相单脉冲调制单相半桥2、方波变换器B 三相180度导通120度导通&#xff08;线、相的关系与180度相反&#xff09;3、阶梯波逆变器独立直流源二极管钳…

BLIP2-图像文本预训练

文章目录摘要解决问题算法模型结构通过frozen图像编码器学习视觉语言表征图像文本对比学习&#xff08;ITC&#xff09;基于图像文本生成&#xff08;ITG&#xff09;图文匹配&#xff08;ITM&#xff09;从大规模语言模型学习视觉到语言生成模型预训练预训练数据预训练图像编码…

Gehpi的网络布局

Gehpi的网络布局1. 力引导布局2. 辅助布局布局是网络可视化中的重要概念&#xff0c;指将点和边通过某种策略进行排布&#xff0c;应尽可能满足以下4个原则&#xff1a; 节点均匀分布在有限的区域内避免边的交叉和弯曲保持边的长度一致整体布局能反映图内在的特性 Gephi的布局…

Vision Transformer学习了什么-WHAT DO VISION TRANSFORMERS LEARN? A VISUAL EXPLORATION

WHAT DO VISION TRANSFORMERS LEARN? A VISUAL EXPLORATION 文章地址 代码地址 摘要 视觉转换器( Vision Transformers&#xff0c;ViTs )正在迅速成为计算机视觉的事实上的架构&#xff0c;但我们对它们为什么工作和学习什么知之甚少。虽然现有研究对卷积神经网络的机制进…

Bunifu.UI.WinForms 6.0.2 Crack

Bunifu.UI.WinForms为 WinForms创建令人惊叹的UI Bunifu.UI.WinForms我们为您提供了现代化的快速用户界面控件。用于 WinForms C# 和 VB.NET 应用程序开发的完美 UI 工具 简单 Bunifu.UI.WinForms没有臃肿的特征。正是您构建令人惊叹的 WinForms 应用程序所需要的。只需拖放然…

JavaSe第3次笔记

1.String str "hello";字符串类型。 2.两个字符串类型相加意思是拼接&#xff0c;类似于c语言里面的strcat函数。 3.整型变成字符串类型: int a 10; String str String. valueOf(a); 4.当字符串和其他类型进行相加的时候&#xff0c;结果就是字符串。(不完全…

MS9132是一款USB 3 0投屏芯片,内部集成USB 3 0 Device控制器、数据收发模块、音视频处理模块

MS9132是一款USB 3.0投屏芯片&#xff0c;内部集成USB 3.0 Device控制器、数据收发模块、音视频处理模块。MS9132可以通过USB 3.0接口将PC、智能手机、平板电脑上的信息显示或扩展到更大尺寸的显示设备&#xff0c;支持HDMI视频接口输出。 主要功能特征 HDMI 1.4b兼容 支持EDI…

RK3568编译Android11和目录讲解

文章目录 前言一、下载android11源码二、环境搭建1.增加交换内存三、编译瑞芯微原厂源码四、目录讲解总结前言 本文记录在Ubuntu18.04中编译Android11,只有编译了源码,后面才能进行驱动的开发,有兴趣的小伙伴可以和我一起学习吧! 提示:以下是本篇文章正文内容,下面案例可…

【华为OD机试模拟题】用 C++ 实现 - 剩余可用字符集 or @分割可用字符集(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 获得完美走位(2023.Q1) 文章目录 最近更新的博客使用说明剩余可用字符集 or @分割可用字符集题目输入输出示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才…

烙铁使用方法

烙铁使用 烙铁是硬件工程师最经常使用的工具之一,一把性能保持良好的烙铁能帮助我们快速进行电路调试。烙铁第一次加热时采用焊锡均匀涂覆在烙铁头上,以便去除包在烙铁头上面的氧化物。在工作中我们需要根据情况选择合适的烙铁头类型,合适的温度进行操作。完成焊接后要在烙铁…

华为OD机试用Python实现 -【贪心的商人 or 最大利润】(2023-Q1 新题)

华为OD机试题 华为OD机试300题大纲贪心的商人 or 最大利润题目描述输入描述输出描述说明示例一输入输出示例二输入输出Python 代码实现华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.c…

基于SpringCloud的可靠消息最终一致性01:定理、解决方案和框架

在互联网发展的早期,单体架构是主流的开发模式。因为访问的用户不多,所以整个系统的结构比较简单,就像一口竖井,从上到下,一通到底,如下图所示: 图一:单体应用 随着业务复杂度的不断提升,以及用户需求的不断增加,原来单个的业务系统已经不堪重负了。就好像一个窗口前…

MS9123是一款单芯片USB投屏器,内部集成了USB2 0控制器和数据收发模块、视频DAC和音视频处理模块,MS9123可以通过USB接口显示或者扩展PC、

MS9123是一款单芯片USB投屏器&#xff0c;内部集成了USB2.0控制器和数据收发模块、视频DAC和音视频处理模块&#xff0c;MS9123可以通过USB接口显示或者扩展PC、智能手机、平板电脑的显示信息到更大尺寸的显示设备上&#xff0c;支持CVBS、S-Video视频接口。 主要功能特征 C…

ChatGPT的互补工具Perplexity的详细使用方法(持续更新)

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,科大讯飞比赛第三名,CCF比赛第四名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

华为OD机试用Python实现 -【云短信平台优惠活动】(2023-Q1 新题)

华为OD机试题 华为OD机试300题大纲云短信平台优惠活动题目描述输入描述输出描述示例一输入输出说明示例二输入输出说明Python 代码实现代码编写思路华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看…