起因
笔者有一个项目,由于用户的不断增加,需要对用户及相关信息做一个后台管理软件。由于笔者之前技术栈是linux后端开发,实话说对web应用一窍不通😅,因此,借此机会学习一下。
web应用
一个合格的管理后台,本质上就是一个web应用(通过浏览器来实现功能的应用)。
web应用根据技术不同可以分为以下几种实现方式:
技术模式 | 适合的应用类型 | 是否需要搜索引擎优化 | 内容更新频率 | 开发复杂度 |
---|---|---|---|---|
SPA单页应用 | 管理后台、Web 工具 | ❌ 否 | 高 | ⭐⭐⭐ |
MPA多页应用 | 内容展示、新闻类网站 | ✅ 是 | 低 | ⭐ |
SSR服务端渲染 | 电商首页、SEO 页 | ✅ 是 | 中 | ⭐⭐⭐⭐ |
SSG静态站点生成 | 博客、官网、文档 | ✅ 是 | 低 | ⭐⭐ |
ISR渐进式静态生成 | 海量内容平台 | ✅ 是 | 中高 | ⭐⭐⭐⭐⭐ |
web应用的实现方式
对于绝大部分web应用来说,不管是SPA还是其他,都需要前端+后端来实现功能。
前端
前端: 负责页面展示、用户交互、与后端的数据通信等。通常使用 HTML、CSS、JavaScript 或其他现代前端框架(如 Vue.js、React、Angular)来构建。
后端
后端: 负责业务逻辑、数据库操作、数据处理等。可以使用 Node.js、Django、Flask、Java、Ruby on Rails 等技术栈来开发后端应用。
例如,前端使用HTML+JS实现一些基本功能,后端使用go编写的http服务端。
func main() {
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("../html/login.html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl.Execute(w, nil)
})
...
fs := http.FileServer(http.Dir("../html"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.Handle("/", fs)
http.ListenAndServe(":8082", nil)
}
当时并没有对web开发有一个整体上的认识,因此开发时借助AI快速开发完成。以为 Web 开发不过如此,实以浅尝辄止,坐井观天😵。
框架选型
使用框架,可以提供一些常见的功能,避免重复造轮子;另外,许多框架内置了一些常见的安全防护措施(如防止 XSS、CSRF 攻击等),大大减少了开发者在实现安全功能时的压力。目前有很多优秀的前后端框架,例如我们听过的Node.js,vue等都是主流的框架。
Node.js主要用于构建高性能的后端 HTTP服务器,常用于构建 RESTful APIs 和 GraphQL APIs,作为前后端通信的中间层,特别是在需要处理大量并发请求和实时交互的场景下非常高效。
Vue.js主要功能是帮助开发者构建交互丰富的前端界面,提供高效的数据绑定和组件化开发,是一款非常常用的前端框架。
针对管理后台来说,github上后很多优秀稳定的框架,实现了大部分功能。
前端选用SoybeanAdmin:https://github.com/soybeanjs/soybean-admin
后端采用rust开发的Axum:https://github.com/tokio-rs/axum
SoybeanAdmin
SoybeanAdmin是基于vue3开发的,因此,需要先安装依赖,包括nodejs和visio studio等。
SoybeanAdmin和后端通信的接口已经定义完成,开发者需要找到这个定义然后根据结构,在后端设置对应的返回就可以。
路由管理
SoybeanAdmin支持静态路由和动态路由。
设置静态路由时,路由表是写死的,前端打包的时候就定好了有哪些页面。设置constant: true的页面不登陆就能访问,其他页面登录之后全部可以访问。
而动态路由模式下,前端页面启动后会向后端请求路由表,根据用户权限动态加载哪些页面可以访问。后端将路由分为公共路由和权限路由两部分,公共路由无需登录,比如 /login、/404,这些放在 fetchGetConstantRoutes 接口里,由后端返回;需要登录的路由放在fetchGetUserRoutes 接口里,登录成功后根据角色动态返回。
对于角色控制不太严格的功能,可以使用静态路由。
Axum
Axum 是一个用 Rust语言 写的,专门用来构建**高性能 Web 服务(API服务器)**的框架。由 Tokio 团队(Rust里著名的异步运行时 Tokio)开发和维护。
针对Rust语言的内存安全以及高并发特性,我们可以单独出一篇文章来和c++做一个对比。
目录设置
- cargo new aumx新建一个项目
- 添加依赖
- 构建目录,可以适当简化
src/
├── main.rs // 启动文件,程序入口
├── api/
│ ├── mod.rs // API 路由总入口
│ ├── health_check.rs // 健康检查路由
│ ├── target.rs // 目标相关的 API
│ └── user.rs // 用户相关的 API
├── handlers/
│ ├── mod.rs // 处理程序入口
│ ├── target_handler.rs // 处理目标相关逻辑
│ └── user_handler.rs // 处理用户相关逻辑
├── models/
│ ├── mod.rs // 数据模型入口
│ ├── target.rs // 目标模型
│ └── user.rs // 用户模型
├── database/
│ ├── mod.rs // 数据库配置和连接池初始化
│ ├── mysql.rs // MySQL 特定的操作(可选)
│ └── migrations.rs // 数据库迁移脚本(可选)
├── middlewares/
│ ├── mod.rs // 中间件入口
│ ├── auth.rs // 认证中间件
│ └── logging.rs // 日志中间件
└── config/
├── mod.rs // 配置文件读取和初始化
└── app_config.rs // 应用相关配置(如端口、环境变量等)
代码编写
对于大部分简单web后端,其主要就是一个http服务器,接收客户端发送的请求,进行路由转发以及逻辑处理。
对于大型的web后端,还需要中间件支持,状态管理与会话控制,负载均衡与高可用性,高并发支持等。
Axum 请求处理
#[tokio::main]
async fn main() {
config::load_config();
// 启动服务器,监听 8080 端口
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
简简单单一句话,即可实现http服务器
当然还可以设置一些数据库连接,配置文件获取等
// 获取数据库连接 URL
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
println!("Database URL: {}", db_url);
// 初始化数据库连接池
let pool = database::database_init(&db_url).await;
// 将连接池包装成 Arc 以便共享
let shared_pool = Arc::new(pool);
路由设置
创建路由:
// 创建路由并传入连接池
let app = api::create_routes(shared_pool);
由于需要连接数据库,因此需要把数据库连接池绑定到路由对象
pub fn create_routes(pool: Arc<sqlx::MySqlPool>) -> Router {
Router::new()
.route("/api/login", post(user::handle_login))
.route("/api/home", get(user::handle_home))
}
路由转发也比较简单,依次填入路由地址,请求方法和处理方法即可
数据处理
对于不同的请求方法,使用不同的传入结构体,例如,post请求需要传入JSON结构体,get请求需要传入Query结果体
pub async fn handle_login(
State(config): State<Arc<AppConfig>>,
Json(payload): Json<LoginPayload>,
) -> Result<Json<ApiResponse<LoginToken>>, StatusCode> {
...
}
整体来说,Axum很适合小白,笔者用了两天就搭建起了一个web后台服务,很多设置都是直接填入即可。
nginx
如果部署到云端,不要忘记最后设置nginx。
前端向后端服务或者数据库请求时,分为两种情况:
连接到80http或者443https先到nginx,然后由nginx进行内部转发。外部客户端只能看到Nginx的端口
http或https直接连接到后端,例如后端http(不安全)或https服务器制定了/api/select这个路由,此时如果后端服务的端口开放,则可以直接进行请求。
第一种更安全,nginx反向代理不会暴露端口。