当前位置: 首页 > wzjs >正文

网站建站和维护广州必去十大景点排名

网站建站和维护,广州必去十大景点排名,做网站都需要年服务费吗,电子商务网站建设应用Rust Web 全栈开发(四):构建 REST APIRust Web 全栈开发(四):构建 REST API构建的内容构建项目健康检查POST 资源:添加课程GET 资源:查询课程查询指定老师的所有课程查询指定老师的指…

Rust Web 全栈开发(四):构建 REST API

  • Rust Web 全栈开发(四):构建 REST API
    • 构建的内容
    • 构建项目
    • 健康检查
    • POST 资源:添加课程
    • GET 资源:查询课程
      • 查询指定老师的所有课程
      • 查询指定老师的指定课程
    • 尾声

Rust Web 全栈开发(四):构建 REST API

参考视频:https://www.bilibili.com/video/BV1RP4y1G7KF

需要使用的 crate:

  • serde
  • chrono

构建的内容

构建一个教师课程的 WebService,支持 3 种请求,每个请求对应一个 Handler:

  1. POST:/courses,提交一个课程
  2. GET:/courses/teacher_id,查询老师的所有课程
  3. GET:/courses/teacher_id/course_id,查询老师的一个课程的详细信息

在这里插入图片描述

构建项目

相关文件:

  • bin/teacher_service.rs
  • models.rs
  • state.rs
  • routers.rs
  • handlers.rs

继续使用上一节的项目。

在 webservice/src 目录下,创建 models.rs、state.rs、routers.rs、handlers.rs。

打开 webservice/Cargo.toml,添加一个 bin 的声明:

[[bin]]
name = "teacher_service"

打开 webservice/Cargo.toml,在 [package] 部分添加:

default-run = "teacher_service"

这样设置后, 当我们不带参数运行 webservice 包时,它默认执行 teacher_service.rs 中的代码。

在 webservice/src/bin 目录下创建 teacher_service.rs。

健康检查

打开 state.rs,编写代码:

use std::sync::Mutex;pub struct AppState {pub health_check_response: String,pub visit_count: Mutex<u32>,
}

AppState 代表应用程序的状态。因为我们使用了 Actix 框架,在请求时应用程序的状态会被注入到 Handler 中,于是在处理请求时 Handler 能获取到 AppState。

health_check_response 是健康检查响应,不可变,在所有线程中共享。visit_count 是访问次数,可变,可以在线程间安全共享。

打开 routers.rs,编写代码:

use super::handlers::*;
use actix_web::web;pub fn general_routes(cfg: &mut web::ServiceConfig) {cfg.route("/health", web::get().to(health_check_handler));
}

打开 handlers.rs,编写代码:

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)
}

互斥锁在 health_check_handler 函数结束时自动释放。

打开 teacher_service.rs,编写代码:

use actix_web::{web, App, HttpServer};
use std::io;
use std::sync::Mutex;#[path = "../handlers.rs"]
mod handlers;
#[path = "../routers.rs"]
mod routers;
#[path = "../state.rs"]
mod state;use routers::*;
use state::AppState;#[actix_rt::main]
async fn main() -> io::Result<()> {let shared_data = web::Data::new(AppState {health_check_response: "I'm OK.".to_string(),visit_count: Mutex::new(0),});let app = move || {App::new().app_data(shared_data.clone()).configure(general_routes)};HttpServer::new(app).bind("127.0.0.1:3000")?.run().await
}

构建 APP 时,把 shared_data(也就是一个 AppState 实例)作为参数传递进去了。

在终端执行命令 cargo run -p webservice,因为之前的设置,默认执行 webservice 库中的 teacher_service。

或者 cd 到 webservice 目录,执行命令 cargo run。

在这里插入图片描述

再新建一个终端,cd 到 webservice,执行命令 curl 127.0.0.1:3000/health。

每次执行一次请求,服务器打印一句 incoming for health check。

然后,新终端会打印出完整的响应信息:

在这里插入图片描述

注意 Content 中的内容,每执行一次 curl 127.0.0.1:3000/health 命令,其计数就会加一。

完整输出结果:

在这里插入图片描述

PS C:\Users\81228\Documents\Program\Rust Project\Actix-Workspace\webservice> curl 127.0.0.1:3000/healthStatusCode        : 200
StatusDescription : OK
Content           : "I'm OK. 0 times"
RawContent        : HTTP/1.1 200 OKContent-Length: 17Content-Type: application/jsonDate: Thu, 10 Jul 2025 08:52:34 GMT"I'm OK. 0 times"
Forms             : {}
Images            : {}
InputFields       : {}
Links             : {}                                                                                                                                                              ParsedHtml        : mshtml.HTMLDocumentClass                                                                                                                                        RawContentLength  : 17                                                                                                                                                                                                                                                                                                                                                  PS C:\Users\81228\Documents\Program\Rust Project\Actix-Workspace\webservice> curl 127.0.0.1:3000/healthStatusCode        : 200
StatusDescription : OK
Content           : "I'm OK. 1 times"
RawContent        : HTTP/1.1 200 OKContent-Length: 17Content-Type: application/jsonDate: Thu, 10 Jul 2025 08:52:57 GMT"I'm OK. 1 times"
Forms             : {}
Images            : {}
InputFields       : {}
Links             : {}                                                                                                                                                              ParsedHtml        : mshtml.HTMLDocumentClass                                                                                                                                        RawContentLength  : 17                                                                                                                                                                                                                                                                                                                                                  PS C:\Users\81228\Documents\Program\Rust Project\Actix-Workspace\webservice> curl 127.0.0.1:3000/healthStatusCode        : 200
StatusDescription : OK
Content           : "I'm OK. 2 times"
RawContent        : HTTP/1.1 200 OKContent-Length: 17Content-Type: application/jsonDate: Thu, 10 Jul 2025 08:53:10 GMT"I'm OK. 2 times"
Forms             : {}
Headers           : {[Content-Length, 17], [Content-Type, application/json], [Date, Thu, 10 Jul 2025 08:53:10 GMT]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 17

至此,健康检查的功能就完成了。

POST 资源:添加课程

打开 webservice/Cargo.toml,在 [dependencies] 部分添加:

# Data serialization library
serde = { version = "1.0.144", features = ["derive"] }
# Other utilities
chrono = {version = "0.4.22", features = ["serde"]}

打开 models.rs,编写代码:

use actix_web::web;
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Course {pub teacher_id: i32,pub id: Option<i32>,pub name: String,pub time: Option<NaiveDateTime>,
}impl From<web::Json<Course>> for Course {fn from(course: web::Json<Course>) -> Self {Course {teacher_id: course.teacher_id,id: course.id,name: course.name.clone(),time: course.time,}}
}

Course 结构体存储了课程的相关信息,我们为 Course 实现了 From trait。

修改 state.rs:

use std::sync::Mutex;
use crate::models::Course;pub struct AppState {pub health_check_response: String,pub visit_count: Mutex<u32>,pub courses: Mutex<Vec<Course>>,
}

修改 teacher_service.rs:

use actix_web::{web, App, HttpServer};
use std::io;
use std::sync::Mutex;#[path = "../handlers.rs"]
mod handlers;
#[path = "../models.rs"]
mod models;
#[path = "../routers.rs"]
mod routers;
#[path = "../state.rs"]
mod state;use routers::*;
use state::AppState;#[actix_rt::main]
async fn main() -> io::Result<()> {let shared_data = web::Data::new(AppState {health_check_response: "I'm OK.".to_string(),visit_count: Mutex::new(0),courses: Mutex::new(vec![]),});let app = move || {App::new().app_data(shared_data.clone()).configure(general_routes)};HttpServer::new(app).bind("127.0.0.1:3000")?.run().await
}

到这先像上一节一样测试一下程序,是能成功执行的。

下面编写添加课程的功能。

修改 routers.rs,添加一个公共函数:

pub fn course_routes(cfg: &mut web::ServiceConfig) {cfg.service(web::scope("/courses").route("/", web::post().to(new_course)));
}

我们声明了 /courses 范围,在该范围内再接着 / 路径,则执行 POST 请求,由 new_course 这个 Handler 进行处理。

这个 course_routes 同样需要注册,在 teacher_service.rs 的 main 函数的 .configure(general_routes) 语句后加上 .configure(course_routes)。

修改 handlers.rs,new_course 函数实现了新增课程的功能:

use super::state::AppState;
use actix_web::{web, HttpResponse};
use super::models::Course;
use chrono::Utc;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)
}pub async fn new_course(new_course: web::Json<Course>,app_state: web::Data<AppState>,
) -> HttpResponse {println!("Received new course");let course_count = app_state.courses.lock().unwrap().clone().into_iter().filter(|course| course.teacher_id == new_course.teacher_id)//.collect::<Vec<Course>>()//.len();.count();let new_course = Course {teacher_id: new_course.teacher_id,id: Some(course_count + 1),name: new_course.name.clone(),time: Some(Utc::now().naive_utc()), // 当前时间};app_state.courses.lock().unwrap().push(new_course);HttpResponse::Ok().json("Course added")
}

最后,为这个功能添加一个测试,在 handlers.rs 的最后加上如下代码:

#[cfg(test)]
mod tests {use super::*;use actix_web::http::StatusCode;use std::sync::Mutex;#[actix_rt::test]async fn post_course_test() {let course = web::Json(Course {teacher_id: 1,name: "Test course".into(),id: None,time: None,});let app_state: web::Data<AppState> = web::Data::new(AppState {health_check_response: "".to_string(),visit_count: Mutex::new(0),courses: Mutex::new(vec![]),});// 模拟添加课程的请求let response = new_course(course, app_state).await;assert_eq!(response.status(), StatusCode::OK);}
}

打开终端,cd 到 webservice,执行命令 cargo test,一个测试通过了:

在这里插入图片描述

我们在一个终端执行命令 cargo run 运行程序,然后在一个 bash 终端执行命令:

curl -X POST localhost:3000/courses/ -H "Content-Type: application/json" -d '{"teacher_id":1, "name":"First course"}'

来模拟一个添加课程的 POST 请求。

在这里插入图片描述

我们看到终端打印 Received new course,bash 终端打印 Course added,说明这个功能成功实现了。

GET 资源:查询课程

查询指定老师的所有课程

修改 routers.rs 中的 course_routes 函数:

pub fn course_routes(cfg: &mut web::ServiceConfig) {cfg.service(web::scope("/courses").route("/", web::post().to(new_course)).route("/{user_id}", web::get().to(get_courses_for_teacher)));
}

新增 /courses/{user_id} 路径,对应一个 GET 请求,对应的 Handler 是 get_courses_for_teacher 函数。

修改 handlers.rs,get_courses_for_teacher 函数实现了查询指定 teacher_id 老师的所有课程的功能:

pub async fn get_courses_for_teacher(app_state: web::Data<AppState>,params: web::Path<i32>,
) -> HttpResponse {// let teacher_id: usize = params.0;let teacher_id: i32 = params.into_inner();let filtered_courses = app_state.courses.lock().unwrap().clone().into_iter().filter(|course| course.teacher_id == teacher_id).collect::<Vec<Course>>();if filtered_courses.len() > 0 {HttpResponse::Ok().json(filtered_courses)} else {HttpResponse::Ok().json("No courses found for teacher".to_string())}
}

在 handlers.rs 的 test 模块为这个功能也添加一个测试:

    #[actix_rt::test]async fn get_all_courses_success() {let app_state: web::Data<AppState> = web::Data::new(AppState {health_check_response: "".to_string(),visit_count: Mutex::new(0),courses: Mutex::new(vec![]),});let teacher_id: web::Path<usize> = web::Path::from(1);let response = get_courses_for_teacher(app_state, teacher_id).await;assert_eq!(response.status(), StatusCode::OK);}

打开终端,cd 到 webservice,执行命令 cargo test,两个测试都通过了:

在这里插入图片描述

因为测试是顺序执行的,在第一个测试中插入了一个 teacher_id 为 1 的课程,所以第二个测试中查询 teacher_id 为 1 的课程可以通过。

我们在一个终端执行命令 cargo run 运行程序,然后在一个 bash 终端执行命令:

curl -X POST localhost:3000/courses/ -H "Content-Type: application/json" -d '{"teacher_id":1, "name":"First course"}'

来模拟一个添加课程的 POST 请求。

再在 bash 终端执行命令:

curl localhost:3000/courses/1

我们可以看到 bash 终端成功打印出了查询课程的信息:[{“teacher_id”:1,“id”:1,“name”:“First course”,“time”:“2025-07-10T11:47:21.168336600”}]

在这里插入图片描述

说明这个功能成功实现了。

查询指定老师的指定课程

修改 routers.rs 中的 course_routes 函数:

pub fn course_routes(cfg: &mut web::ServiceConfig) {cfg.service(web::scope("/courses").route("/", web::post().to(new_course)).route("/{user_id}", web::get().to(get_courses_for_teacher)).route("/{user_id}/{course_id}", web::get().to(get_course_detail)));
}

新增 /courses/{user_id}/{course_id} 路径,对应一个 GET 请求,对应的 Handler 是 get_course_detail 函数。

修改 handlers.rs,get_course_detail 函数实现了查询指定 teacher_id 老师的指定 course_id 课程的功能:

pub async fn get_course_detail(app_state: web::Data<AppState>,params: web::Path<(i32, i32)>,
) -> HttpResponse {let (teacher_id, course_id) = params.into_inner();let selected_course = app_state.courses.lock().unwrap().clone().into_iter().find(|course| course.teacher_id == teacher_id && course.id == Some(course_id)).ok_or("Course not found");if let Ok(course) = selected_course {HttpResponse::Ok().json(course)} else {HttpResponse::Ok().json("Course not found".to_string())}
}

在 handlers.rs 的 test 模块为这个功能也添加一个测试:

    #[actix_rt::test]async fn get_one_course_success() {let app_state: web::Data<AppState> = web::Data::new(AppState {health_check_response: "".to_string(),visit_count: Mutex::new(0),courses: Mutex::new(vec![]),});let params: web::Path<(i32, i32)> = web::Path::from((1, 1));let resp = get_course_detail(app_state, params).await;assert_eq!(resp.status(), StatusCode::OK);}

打开终端,cd 到 webservice,执行命令 cargo test,三个测试都通过了:

在这里插入图片描述

我们在一个终端执行命令 cargo run 运行程序,然后在一个 bash 终端执行命令:

curl -X POST localhost:3000/courses/ -H "Content-Type: application/json" -d '{"teacher_id":1, "name":"First course"}'
curl -X POST localhost:3000/courses/ -H "Content-Type: application/json" -d '{"teacher_id":1, "name":"Second course"}'

来模拟两个添加课程的 POST 请求。

再在 bash 终端执行命令:

curl localhost:3000/courses/1/2

我们可以看到 bash 终端成功打印出了查询课程的信息:{“teacher_id”:1,“id”:2,“name”:“Second course”,“time”:“2025-07-10T11:51:18.608348”}

在这里插入图片描述

说明这个功能成功实现了。

尾声

按 视频教程 的写法,Course 结构体声明为:

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Course {pub teacher_id: usize,pub id: Option<usize>,pub name: String,pub time: Option<NaiveDateTime>,
}

取值用的是 params.0,例如,handlers.rs 中的 get_courses_for_teacher 函数长这样:

pub async fn get_courses_for_teacher(app_state: web::Data<AppState>,params: web::Path<usize>,
) -> HttpResponse {let teacher_id: usize = params.0;let filtered_courses = app_state.courses.lock().unwrap().clone().into_iter().filter(|course| course.teacher_id == teacher_id).collect::<Vec<Course>>();if filtered_courses.len() > 0 {HttpResponse::Ok().json(filtered_courses)} else {HttpResponse::Ok().json("No courses found for teacher".to_string())}
}

这样做会出现报错:

在这里插入图片描述

有几处不同的地方,改成前文我写的那样才行。

这里给出原版教程的官方源码地址:

https://github.com/peshwar9/rust-servers-services-apps/tree/master

后续如果还出现这种情况,建议对比源码看看。


文章转载自:

http://p9xInWJ5.rmrcc.cn
http://wghf3rKP.rmrcc.cn
http://ZmHnMfVx.rmrcc.cn
http://3q9tscs8.rmrcc.cn
http://y2iIEfTR.rmrcc.cn
http://69caZKp6.rmrcc.cn
http://vrkeXJ4X.rmrcc.cn
http://nJbYUXXo.rmrcc.cn
http://U7hdLZnw.rmrcc.cn
http://VwBLfBDY.rmrcc.cn
http://vWoJ1T0O.rmrcc.cn
http://wtk5mvrT.rmrcc.cn
http://YV5OBpmB.rmrcc.cn
http://2v8LXvGA.rmrcc.cn
http://yN18uzeG.rmrcc.cn
http://DfWV3psm.rmrcc.cn
http://pBCe5G3D.rmrcc.cn
http://tIpoOvuI.rmrcc.cn
http://rqKEyHL6.rmrcc.cn
http://Av6ROME3.rmrcc.cn
http://L2HEG08m.rmrcc.cn
http://Xuyd1Y8f.rmrcc.cn
http://flzrwx2J.rmrcc.cn
http://UXTmQUlx.rmrcc.cn
http://JfaF30yj.rmrcc.cn
http://EPkuL6RL.rmrcc.cn
http://02WotGod.rmrcc.cn
http://QAuxctQM.rmrcc.cn
http://h6rMGrs8.rmrcc.cn
http://TW4USTQH.rmrcc.cn
http://www.dtcms.com/wzjs/665927.html

相关文章:

  • 网站开发流程比较合理企业管理培训课程定制
  • 做侵权视频网站自己怎样做广告链接
  • 淘宝网站制作多少钱长春网站建设技术托管
  • php网站开发用什么ide湘潭网站建设企业
  • 网站域名查企业邮箱自适应网站建设电话
  • 建筑施工证查询网站网站受攻击
  • 辽阳市网站建设网站假设教程
  • 建站知乎网站建设公司哪家好 在线磐石网络
  • 商业网站模板下载唐山网站建设设计
  • 做网站盐城商城网站建设招聘
  • 网站建设站花西子的网络营销策略
  • 英文网站seo如何做广东餐饮品牌设计
  • 网站开发培训哪里好凡科网让经营更简单
  • 网站建设预算知乎烟花代码编程python
  • 娄底网站推广微博推广的好处
  • 常平东莞网站设计外网不能访问wordpress
  • 有什么好的网站设计思想的博客做网站muse好还是DW好用
  • 一个网站备案号是冒用其它公司的重庆做网站的
  • 国外旅游网站排名番禺做网站
  • 上海网站建设乐云seo韩国网站建站
  • 免费发布信息网网站公司网络维修
  • 墨星写作网站app下载江西核工业建设有限公司网站
  • 给人做ppt的网站吗两学一做专题网站素材
  • 云县网站建设关于进一步加强门户网站建设
  • 做网站阿里云买哪个服务器好点广州做和改版网站的公司
  • 做网站的心得体会搜索引擎优化行业
  • 查询建设资质的网站建购物网站多少钱
  • 自己做视频网站怎么处理高并发网站截图环境 php
  • 光明新区城市建设局网站今天发生的国际新闻
  • 宁波高端网站建设公司wordpress如何转换为中文版