'# Node.js 机场保障车辆报修app
一、背景与问题
在机场运营场景中,保障车辆(如除冰车、牵引车、电源车等)的正常运行直接关系到航班起降效率。传统报修系统存在以下痛点:
- 纸质单据填写耗时,信息传递延迟
- 系统无法实时同步车辆状态
- 报修工单缺乏优先级管理
- 无法追溯维修历史记录
- 多部门协同工作缺乏统一平台
Node.js作为JavaScript运行时,具备异步非阻塞特性,能有效处理高并发的实时通信需求。通过构建基于Node.js的机场保障车辆报修系统,可以实现:
- 实时工单状态更新
- 多端协同工作(移动端/网页端)
- 数据可视化分析
- 自动化工单分配
二、基本原理
系统架构采用分层设计:
[客户端] <-> [Node.js API层] <-> [数据库层] <-> [缓存层]核心组件包括:
- 用户认证系统(JWT)
- 工单管理模块(状态机)
- 实时通信模块(WebSocket)
- 数据分析模块(ECharts集成)
Node.js通过事件循环机制处理大量并发请求,配合MongoDB的文档模型,可以高效存储和查询工单数据。对于实时通知需求,采用WebSocket长连接保持通信。
三、环境准备
# 安装Node.js
nvm install 18
# 创建项目目录
mkdir airport-maintenance
cd airport-maintenance
# 初始化项目
npm init -y
# 安装依赖
npm install express mongoose socket.io jwt jsonwebtoken cors dotenv四、核心实现
1. 用户认证系统
// auth.js
const jwt = require('jsonwebtoken');
const { User } = require('./models');
exports.login = async (req, res) => {
const { username, password } = req.body;
// 1. 数据库查询
const user = await User.findOne({ username });
// 2. 密码验证
if (!user || !(await user.comparePassword(password))) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// 3. 生成JWT
const token = jwt.sign(
{ userId: user._id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
// 4. 返回结果
res.json({ token, user: { id: user._id, name: user.name, role: user.role } });
};关键点说明:
- 使用JWT进行无状态认证
- 密码加密存储(bcrypt)
- token有效期控制
- 基于角色的权限控制
2. 工单状态机管理
// workOrder.js
const { Schema, model } = require('mongoose');
const WorkOrderSchema = new Schema({
title: String,
description: String,
status: {
type: String,
enum: ['pending', 'assigned', 'in_progress', 'completed', 'canceled'],
default: 'pending'
},
assignedTo: String,
createdAt: { type: Date, default: Date.now }
});
// 状态转移规则
WorkOrderSchema.methods.assign = function(userId) {
if (this.status !== 'pending') throw new Error('Invalid status for assignment');
this.status = 'assigned';
this.assignedTo = userId;
return this.save();
};
WorkOrderSchema.methods.complete = function() {
if (this.status !== 'in_progress') throw new Error('Invalid status for completion');
this.status = 'completed';
return this.save();
};
module.exports = model('WorkOrder', WorkOrderSchema);关键点说明:
- 使用状态机模式保证状态转换合法性
- 通过方法封装状态转移逻辑
- 防止无效状态转换
- 支持审计追踪
3. 实时通知系统
// socket.js
const { Server } = require('socket.io');
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Socket.IO server\n');
});
const io = new Server(server, {
cors: {
origin: '*',
methods: ['GET', 'POST']
}
});
io.on('connection', (socket) => {
console.log('Client connected');
// 监听工单状态变更
socket.on('updateWorkOrder', (data) => {
io.emit('workOrderUpdated', data);
});
// 断开连接时的处理
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});关键点说明:
- 使用WebSocket保持长连接
- 广播机制实现通知推送
- 跨域配置支持多端接入
- 支持消息重发机制
五、完整案例
1. 系统流程图
[用户]
├─ 登录 → [认证服务]
├─ 创建工单 → [工单服务]
├─ 查看工单 → [工单服务]
└─ 接收通知 → [通知服务]2. 工单创建流程(完整代码)
// workOrderController.js
const express = require('express');
const router = express.Router();
const { WorkOrder } = require('../models');
const { authenticate } = require('./auth');
router.post('/create', authenticate, async (req, res) => {
try {
const { title, description, vehicleId } = req.body;
// 1. 验证必填字段
if (!title || !description || !vehicleId) {
return res.status(400).json({ error: 'Missing required fields' });
}
// 2. 创建工单
const workOrder = await WorkOrder.create({
title,
description,
vehicleId,
status: 'pending',
createdBy: req.user.id
});
// 3. 推送通知
io.emit('workOrderCreated', workOrder);
res.status(201).json(workOrder);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});3. 前端页面示例(React)
// App.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
function App() {
const [workOrders, setWorkOrders] = useState([]);
useEffect(() => {
// 1. 获取工单列表
axios.get('/api/workorders')
.then(res => setWorkOrders(res.data))
.catch(err => console.error(err));
// 2. 监听通知
const socket = io('http://localhost:3000');
socket.on('workOrderUpdated', (updatedOrder) => {
setWorkOrders(prev =>
prev.map(order =>
order._id === updatedOrder._id ? updatedOrder : order
)
);
});
}, []);
return (
<div>
<h1>工单列表</h1>
<ul>
{workOrders.map(order => (
<li key={order._id}>
{order.title} - {order.status}
</li>
))}
</ul>
</div>
);
}
export default App;六、源码解析
1. 中间件处理流程
// middleware/auth.js
const jwt = require('jsonwebtoken');
function authenticate(req, res, next) {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}关键点说明:
- 从请求头获取token
- 使用JWT验证签名
- 提取用户信息
- 异常处理
2. 工单状态转换逻辑
// workOrder.js
WorkOrderSchema.methods.assign = function(userId) {
// 状态校验
if (this.status !== 'pending') {
throw new Error(`Cannot assign to ${this.status} status`);
}
// 权限校验
if (userId !== this.createdBy) {
throw new Error('Not authorized to assign this work order');
}
// 状态转移
this.status = 'assigned';
this.assignedTo = userId;
// 记录操作日志
this.history.push({
action: 'assign',
timestamp: Date.now(),
user: userId
});
return this.save();
};关键点说明:
- 状态转换前的校验
- 权限控制
- 操作日志记录
- 状态变更的原子性
七、进阶使用
1. 多租户支持
// tenantMiddleware.js
function tenantMiddleware(req, res, next) {
const tenantId = req.headers['x-tenant-id'];
if (!tenantId) {
return res.status(400).json({ error: 'Tenant ID required' });
}
req.tenantId = tenantId;
next();
}2. 消息队列集成
// worker.js
const { Worker } = require('worker_threads');
const { queue } = require('./queue');
queue.add('processWorkOrder', {
id: '123',
type: 'urgent'
});3. 数据分析模块
// analytics.js
const { WorkOrder } = require('./models');
async function getStats() {
const stats = await WorkOrder.aggregate([
{ $match: { status: 'completed' } },
{ $group: {
_id: null,
total: { $sum: 1 },
avgDuration: {
$avg: {
$subtract: [
"$completedAt",
"$createdAt"
]
}
}
} }
]);
return stats[0];
}八、性能与工程实践
1. 性能优化策略
数据库优化:
- 使用索引(vehicleId, status)
- 使用连接池(mongodb://...?maxPoolSize=100)
- 启用缓存(Redis缓存常用状态)
缓存策略:
// 缓存工单状态 const cachedStatus = await redis.get(`workorder:${id}`); if (cachedStatus) return cachedStatus;异步处理:
// 使用队列处理非实时任务 queue.add('sendNotification', { ... });
2. 安全措施
JWT安全:
- 使用HTTPS
- 设置
httpOnly和secure标志 - 禁用
aud和iss验证
防止SQL注入:
// 使用Mongoose自动转义 const user = await User.findOne({ username: req.body.username });防止XSS攻击:
// 使用Content-Security-Policy头 res.setHeader('Content-Security-Policy', "default-src 'self'");
3. 异常处理
// 全局错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
// 捕获未处理的Promise拒绝
if (err instanceof Error) {
res.status(500).json({ error: 'Internal server error' });
}
});九、常见问题与踩坑
1. 常见错误及解决办法
| 问题 | 描述 | 解决方案 |
|---|---|---|
| 1 | WebSocket连接断开 | 检查CORS配置,增加心跳机制 |
| 2 | 工单状态无法更新 | 检查状态机转换规则,增加日志记录 |
| 3 | 登录后无法获取数据 | 检查JWT验证逻辑,确保字段正确 |
| 4 | 系统响应缓慢 | 优化数据库查询,增加缓存 |
2. 状态机设计陷阱
错误示例:
// 错误的状态转换逻辑
if (this.status === 'pending') {
this.status = 'assigned';
} else if (this.status === 'assigned') {
this.status = 'completed';
}改进方案:
// 正确的状态机转换
if (this.status === 'pending') {
this.status = 'assigned';
} else if (this.status === 'assigned') {
this.status = 'in_progress';
} else if (this.status === 'in_progress') {
this.status = 'completed';
}3. 安全风险分析
| 风险类型 | 描述 | 防护措施 |
|---|---|---|
| 跨站脚本攻击(XSS) | 用户输入未过滤 | 使用Content-Security-Policy头 |
| 跨站请求伪造(CSRF) | 未验证请求来源 | 使用JWT令牌和SameSite属性 |
| 祭出密钥泄露 | JWT密钥硬编码 | 使用环境变量和密钥管理服务 |
十、最佳实践
认证安全:
- 使用HTTPS
- 设置JWT有效期
- 禁用敏感字段返回
状态管理:
- 使用状态机模式
- 记录操作日志
- 设置状态转换规则
性能优化:
- 使用缓存
- 优化数据库查询
- 使用连接池
错误处理:
- 全局异常处理
- 日志记录
- 熔断机制
可维护性:
- 使用模块化结构
- 增加单元测试
- 使用版本控制
十一、总结
Node.js在机场保障车辆报修系统中展现了其在高并发、实时通信方面的优势。通过合理设计状态机、使用WebSocket进行实时通信、结合JWT进行身份验证,可以构建一个高效可靠的系统。在实际开发中需要注意安全防护、性能优化和异常处理,避免常见的陷阱。对于需要实时更新、多终端协作的场景,Node.js是一个优秀的选择,但在处理复杂业务逻辑时需要结合其他技术栈(如微服务架构)来完善系统架构。