1. 项目概述
在当今前后端分离的开发模式下,后端API接口的开发效率直接影响整个项目的推进速度。Node.js凭借其非阻塞I/O和事件驱动的特性,特别适合构建高并发的网络应用。而Express作为Node.js最流行的Web框架,以其轻量级和中间件机制闻名,能够帮助开发者快速搭建RESTful API服务。
这个Demo将展示如何从零开始构建一个完整的后端业务接口模块。不同于简单的"Hello World"示例,我们会实现用户管理系统的核心功能,包括:
- 用户注册/登录接口(JWT认证)
- 个人信息CRUD操作
- 数据验证与错误处理
- 数据库集成(MongoDB)
- 接口文档生成
提示:本文假设读者已掌握基本的JavaScript语法和HTTP协议知识。所有代码示例都经过实际验证,可直接用于项目初始化。
2. 环境准备与项目初始化
2.1 开发环境配置
首先确保系统已安装:
- Node.js v16+(推荐使用nvm管理多版本)
- MongoDB 4.4+(本地或云服务)
- Postman/Insomnia(接口测试工具)
创建项目目录并初始化:
bash复制mkdir express-api-demo && cd express-api-demo
npm init -y
2.2 核心依赖安装
安装Express和常用中间件:
bash复制npm install express cors morgan helmet
cors:处理跨域请求morgan:HTTP请求日志helmet:安全头部设置
开发依赖(类型提示和热更新):
bash复制npm install -D typescript @types/node @types/express nodemon
2.3 项目结构设计
采用分层架构组织代码:
code复制/src
/config # 配置文件
/controllers # 业务逻辑
/middlewares # 自定义中间件
/models # 数据模型
/routes # 路由定义
/services # 服务层
/utils # 工具函数
app.ts # 应用入口
server.ts # 服务启动
3. Express应用核心搭建
3.1 基础服务器配置
创建app.ts初始化Express应用:
typescript复制import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
const app = express();
// 中间件配置
app.use(helmet());
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 健康检查路由
app.get('/health', (req, res) => {
res.status(200).json({ status: 'UP' });
});
export default app;
3.2 路由模块化设计
以用户模块为例,创建/routes/user.routes.ts:
typescript复制import { Router } from 'express';
import UserController from '../controllers/user.controller';
const router = Router();
const controller = new UserController();
router.post('/register', controller.register);
router.post('/login', controller.login);
router.get('/:id', controller.getProfile);
router.patch('/:id', controller.updateProfile);
router.delete('/:id', controller.deleteUser);
export default router;
然后在主应用中挂载路由:
typescript复制import userRoutes from './routes/user.routes';
// ...其他配置
app.use('/api/users', userRoutes);
3.3 控制器逻辑实现
创建/controllers/user.controller.ts处理业务逻辑:
typescript复制import { Request, Response } from 'express';
import UserService from '../services/user.service';
export default class UserController {
private service = new UserService();
async register(req: Request, res: Response) {
try {
const user = await this.service.createUser(req.body);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
}
// 其他方法实现...
}
4. 数据层集成
4.1 MongoDB连接配置
使用mongoose进行数据库操作,创建/config/database.ts:
typescript复制import mongoose from 'mongoose';
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI || 'mongodb://localhost:27017/api-demo');
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
};
export default connectDB;
4.2 用户模型定义
创建/models/user.model.ts:
typescript复制import { Schema, model } from 'mongoose';
import bcrypt from 'bcryptjs';
interface IUser {
username: string;
email: string;
password: string;
comparePassword(candidatePassword: string): Promise<boolean>;
}
const userSchema = new Schema<IUser>({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
});
// 密码加密钩子
userSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 12);
next();
});
// 密码比对方法
userSchema.methods.comparePassword = async function(candidatePassword: string) {
return await bcrypt.compare(candidatePassword, this.password);
};
export default model<IUser>('User', userSchema);
5. 认证与安全
5.1 JWT认证实现
安装依赖:
bash复制npm install jsonwebtoken bcryptjs @types/jsonwebtoken @types/bcryptjs
创建/utils/jwt.ts:
typescript复制import jwt from 'jsonwebtoken';
import config from '../config';
export const signToken = (payload: object) => {
return jwt.sign(payload, config.jwtSecret, {
expiresIn: config.jwtExpiresIn
});
};
export const verifyToken = (token: string) => {
return jwt.verify(token, config.jwtSecret);
};
5.2 认证中间件
创建/middlewares/auth.middleware.ts:
typescript复制import { Request, Response, NextFunction } from 'express';
import { verifyToken } from '../utils/jwt';
export default (req: Request, res: Response, next: NextFunction) => {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'Access denied' });
}
try {
const decoded = verifyToken(token);
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
};
6. 错误处理优化
6.1 自定义错误类
创建/utils/error.ts:
typescript复制export class AppError extends Error {
statusCode: number;
constructor(message: string, statusCode: number = 400) {
super(message);
this.statusCode = statusCode;
Error.captureStackTrace(this, this.constructor);
}
}
// 特定错误类型
export class NotFoundError extends AppError {
constructor(message = 'Resource not found') {
super(message, 404);
}
}
6.2 全局错误处理器
在app.ts中添加:
typescript复制import { AppError } from './utils/error';
// ...其他中间件
app.use((err: any, req: Request, res: Response, next: NextFunction) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
res.status(err.statusCode).json({
status: err.status,
message: err.message
});
});
7. 接口测试与文档
7.1 Postman测试集合
建议创建以下测试用例:
- 用户注册(POST /api/users/register)
- 用户登录(POST /api/users/login)
- 获取个人信息(GET /api/users/:id)
- 更新信息(PATCH /api/users/:id)
- 删除账户(DELETE /api/users/:id)
7.2 Swagger文档集成
安装swagger-ui-express:
bash复制npm install swagger-ui-express swagger-jsdoc @types/swagger-ui-express
创建/utils/swagger.ts:
typescript复制import swaggerJsdoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express';
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Express API Demo',
version: '1.0.0',
},
},
apis: ['./src/routes/*.ts'], // 扫描路由文件中的注释
};
const specs = swaggerJsdoc(options);
export default (app: express.Application) => {
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
};
在路由中添加JSDoc注释示例:
typescript复制/**
* @swagger
* /api/users/register:
* post:
* summary: 注册新用户
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* username:
* type: string
* email:
* type: string
* password:
* type: string
* responses:
* 201:
* description: 用户创建成功
*/
router.post('/register', controller.register);
8. 项目优化与部署
8.1 环境变量管理
使用dotenv管理敏感信息:
bash复制npm install dotenv
创建.env文件:
code复制MONGO_URI=mongodb://localhost:27017/api-demo
JWT_SECRET=your-secret-key
JWT_EXPIRES_IN=30d
PORT=3000
8.2 性能优化技巧
- 使用compression中间件压缩响应:
bash复制npm install compression @types/compression
typescript复制import compression from 'compression';
app.use(compression());
- 实现请求速率限制:
bash复制npm install express-rate-limit
typescript复制import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100 // 每个IP限制100次请求
});
app.use(limiter);
8.3 PM2生产环境部署
全局安装PM2:
bash复制npm install -g pm2
创建启动脚本ecosystem.config.js:
javascript复制module.exports = {
apps: [{
name: 'api-server',
script: './dist/server.js',
instances: 'max',
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production'
}
}]
};
启动集群模式:
bash复制npm run build
pm2 start ecosystem.config.js
9. 常见问题与解决方案
9.1 跨域问题深度处理
虽然cors中间件解决了基本跨域问题,但在以下场景需要特别注意:
- 凭证模式(withCredentials):
typescript复制app.use(cors({
origin: ['http://localhost:3000'],
credentials: true
}));
- 预检请求缓存:
typescript复制app.use(cors({
maxAge: 86400 // 预检请求缓存24小时
}));
9.2 文件上传实现
安装multer处理文件上传:
bash复制npm install multer @types/multer
创建上传中间件:
typescript复制import multer from 'multer';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}-${file.originalname}`);
}
});
const upload = multer({ storage });
// 在路由中使用
router.post('/avatar', upload.single('avatar'), controller.uploadAvatar);
9.3 数据库连接池优化
Mongoose连接配置优化:
typescript复制mongoose.connect(uri, {
maxPoolSize: 50, // 连接池大小
wtimeoutMS: 2500,
socketTimeoutMS: 60000,
serverSelectionTimeoutMS: 5000
});
10. 项目扩展方向
- 单元测试集成:添加Jest测试框架
- GraphQL支持:集成Apollo Server
- 微服务架构:拆分为独立服务
- Docker容器化:创建Dockerfile
- 日志集中管理:集成ELK栈
- API监控:添加Prometheus指标
实际开发中,我发现合理的目录结构和清晰的中间件分层能显著提升项目可维护性。特别是在团队协作时,约定统一的错误处理方式和响应格式可以减少很多沟通成本。对于刚开始使用Express的开发者,建议先从这个小而全的Demo入手,理解各个模块的职责边界,再逐步扩展到更复杂的业务场景。