欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 【Node.js】全栈开发实践

【Node.js】全栈开发实践

2025/5/23 11:17:41 来源:https://blog.csdn.net/Go_ahead1025/article/details/148126916  浏览:    关键词:【Node.js】全栈开发实践

在这里插入图片描述

个人主页:Guiat
归属专栏:node.js

在这里插入图片描述

文章目录

  • 1. Node.js 全栈开发概述
    • 1.1 全栈开发的优势
    • 1.2 Node.js 全栈开发技术栈
  • 2. 开发环境搭建
    • 2.1 Node.js 和 npm 安装
    • 2.2 开发工具安装
    • 2.3 版本控制设置
    • 2.4 项目初始化流程
  • 3. 后端开发 (Node.js)
    • 3.1 Express 框架基础
    • 3.2 RESTful API 设计
    • 3.3 中间件开发
    • 3.4 数据库集成
    • 3.5 身份验证和授权
    • 3.6 后端架构
  • 4. 前端开发
    • 4.1 React 基础
    • 4.2 状态管理 (Redux)
    • 4.3 API 请求处理
    • 4.4 前端路由 (React Router)
    • 4.5 前端架构
  • 5. 全栈集成
    • 5.1 前后端通信
    • 5.2 身份验证流程
    • 5.3 完整的全栈应用架构
  • 6. 数据建模与持久化
    • 6.1 MongoDB 数据模型
    • 6.2 MySQL 数据建模
    • 6.3 数据关系建模
  • 7. API 开发与设计模式
    • 7.1 模块化路由
    • 7.2 控制器模式
    • 7.3 服务层模式
    • 7.4 错误处理模式
  • 8. 安全性与性能优化
    • 8.1 安全最佳实践
    • 8.2 性能优化技术
    • 8.3 日志系统
  • 9. 部署与 DevOps
    • 9.1 Docker 容器化
    • 9.2 CI/CD 流水线
    • 9.3 部署流程

正文

1. Node.js 全栈开发概述

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,使开发者能够使用 JavaScript 进行服务器端编程。全栈开发指的是同时处理前端和后端的开发工作。

1.1 全栈开发的优势

  • 使用统一的语言(JavaScript)开发前后端
  • 减少技术栈上下文切换成本
  • 提高开发效率和代码复用性
  • 便于小团队快速构建完整应用
  • 简化部署和维护流程

1.2 Node.js 全栈开发技术栈

Node.js全栈技术栈
前端技术
后端技术
数据库技术
开发工具
部署技术
React/Vue/Angular
HTML/CSS
TypeScript
Express/Koa/NestJS
GraphQL
RESTful API
MongoDB
MySQL/PostgreSQL
Redis
npm/Yarn
Webpack/Vite
Git
Docker
AWS/Azure/GCP
CI/CD管道

2. 开发环境搭建

2.1 Node.js 和 npm 安装

Node.js 是全栈开发的基础环境,npm 是其包管理工具。

# 安装 Node.js 和 npm (macOS)
brew install node# 安装 Node.js 和 npm (Ubuntu)
sudo apt update
sudo apt install nodejs npm# 安装 Node.js 和 npm (Windows)
# 从 https://nodejs.org 下载安装程序# 验证安装
node --version
npm --version

2.2 开发工具安装

良好的开发工具可以提高开发效率:

# 安装常用全局工具
npm install -g nodemon # 自动重启服务器
npm install -g ts-node # TypeScript 执行环境
npm install -g create-react-app # React 项目生成器
npm install -g @vue/cli # Vue 项目生成器
npm install -g prettier # 代码格式化工具

2.3 版本控制设置

Git 是最流行的版本控制系统:

# 初始化 Git 仓库
git init# 创建 .gitignore 文件
echo "node_modules/\n.env\n.DS_Store\ndist/\nbuild/" > .gitignore# 配置用户信息
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

2.4 项目初始化流程

项目初始化
创建项目目录
初始化npm
创建基本目录结构
安装依赖
配置环境变量
编写启动脚本
初始化Git仓库

3. 后端开发 (Node.js)

3.1 Express 框架基础

Express 是 Node.js 最流行的 Web 应用框架之一。

// 基本 Express 服务器
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));// 路由
app.get('/', (req, res) => {res.send('Hello World!');
});// 启动服务器
app.listen(PORT, () => {console.log(`Server running on port ${PORT}`);
});

3.2 RESTful API 设计

RESTful API 是一种软件架构风格,用于设计网络应用。

// 用户资源的 RESTful API
const express = require('express');
const router = express.Router();// 获取所有用户
router.get('/users', (req, res) => {// 实现获取所有用户的逻辑res.json({ users: [] });
});// 获取单个用户
router.get('/users/:id', (req, res) => {const userId = req.params.id;// 实现获取单个用户的逻辑res.json({ user: { id: userId } });
});// 创建用户
router.post('/users', (req, res) => {const userData = req.body;// 实现创建用户的逻辑res.status(201).json({ user: userData });
});// 更新用户
router.put('/users/:id', (req, res) => {const userId = req.params.id;const userData = req.body;// 实现更新用户的逻辑res.json({ user: { id: userId, ...userData } });
});// 删除用户
router.delete('/users/:id', (req, res) => {const userId = req.params.id;// 实现删除用户的逻辑res.status(204).end();
});module.exports = router;

3.3 中间件开发

中间件是 Express 中处理请求和响应的功能模块。

// 认证中间件
const jwt = require('jsonwebtoken');const authMiddleware = (req, res, next) => {const token = req.header('Authorization')?.replace('Bearer ', '');if (!token) {return res.status(401).json({ message: '未提供访问令牌' });}try {const decoded = jwt.verify(token, process.env.JWT_SECRET);req.user = decoded;next();} catch (error) {return res.status(401).json({ message: '无效的访问令牌' });}
};// 错误处理中间件
const errorHandlerMiddleware = (err, req, res, next) => {console.error(err.stack);// 自定义错误响应if (err.name === 'ValidationError') {return res.status(400).json({ message: err.message });}res.status(500).json({ message: '服务器内部错误' });
};module.exports = { authMiddleware, errorHandlerMiddleware };

3.4 数据库集成

Node.js 可以与各种数据库集成。

// MongoDB 集成 (使用 Mongoose)
const mongoose = require('mongoose');// 连接 MongoDB
mongoose.connect(process.env.MONGODB_URI, {useNewUrlParser: true,useUnifiedTopology: true,
})
.then(() => console.log('MongoDB 连接成功'))
.catch((err) => console.error('MongoDB 连接失败:', err));// 定义用户模型
const userSchema = new mongoose.Schema({username: {type: String,required: true,unique: true,trim: true,},email: {type: String,required: true,unique: true,trim: true,lowercase: true,},password: {type: String,required: true,},createdAt: {type: Date,default: Date.now,},
});const User = mongoose.model('User', userSchema);module.exports = User;
// MySQL 集成 (使用 mysql2)
const mysql = require('mysql2/promise');// 创建连接池
const pool = mysql.createPool({host: process.env.DB_HOST,user: process.env.DB_USER,password: process.env.DB_PASSWORD,database: process.env.DB_NAME,waitForConnections: true,connectionLimit: 10,queueLimit: 0,
});// 用户数据访问对象
const UserDAO = {// 获取所有用户async getAllUsers() {const [rows] = await pool.query('SELECT * FROM users');return rows;},// 通过 ID 获取用户async getUserById(id) {const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);return rows[0];},// 创建用户async createUser(user) {const { username, email, password } = user;const [result] = await pool.query('INSERT INTO users (username, email, password) VALUES (?, ?, ?)',[username, email, password]);return { id: result.insertId, ...user };},
};module.exports = UserDAO;

3.5 身份验证和授权

// JWT 身份验证实现
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const User = require('../models/User');const authController = {// 用户注册async register(req, res) {try {const { username, email, password } = req.body;// 检查是否已存在用户const existingUser = await User.findOne({ $or: [{ username }, { email }] });if (existingUser) {return res.status(400).json({ message: '用户名或邮箱已被使用' });}// 哈希密码const hashedPassword = await bcrypt.hash(password, 10);// 创建新用户const newUser = new User({username,email,password: hashedPassword,});await newUser.save();// 生成 JWTconst token = jwt.sign({ userId: newUser._id, username: newUser.username },process.env.JWT_SECRET,{ expiresIn: '1h' });res.status(201).json({ user: newUser, token });} catch (error) {res.status(500).json({ message: '注册失败', error: error.message });}},// 用户登录async login(req, res) {try {const { username, password } = req.body;// 查找用户const user = await User.findOne({ username });if (!user) {return res.status(401).json({ message: '用户名或密码错误' });}// 验证密码const isPasswordValid = await bcrypt.compare(password, user.password);if (!isPasswordValid) {return res.status(401).json({ message: '用户名或密码错误' });}// 生成 JWTconst token = jwt.sign({ userId: user._id, username: user.username },process.env.JWT_SECRET,{ expiresIn: '1h' });res.json({ user, token });} catch (error) {res.status(500).json({ message: '登录失败', error: error.message });}},
};module.exports = authController;

3.6 后端架构

Express 应用
路由层
中间件层
控制器层
数据访问层
服务层
API 路由
Web 路由
认证路由
身份验证
日志记录
错误处理
CORS
用户控制器
产品控制器
订单控制器
用户仓库
产品仓库
订单仓库
认证服务
电子邮件服务
支付服务
数据库

4. 前端开发

4.1 React 基础

React 是一个用于构建用户界面的 JavaScript 库。

// 创建 React 应用
npx create-react-app my-app
cd my-app
npm start// 简单的 React 组件
import React from 'react';function Welcome(props) {return <h1>Hello, {props.name}</h1>;
}export default Welcome;

4.2 状态管理 (Redux)

Redux 是一个 JavaScript 状态容器,提供可预测的状态管理。

// Redux store 配置
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { userReducer } from './reducers/userReducer';
import { productReducer } from './reducers/productReducer';// 合并 reducers
const rootReducer = combineReducers({user: userReducer,products: productReducer,
});// 创建 store
const store = createStore(rootReducer,applyMiddleware(thunk)
);export default store;// 用户 reducer
const initialState = {currentUser: null,isLoading: false,error: null,
};export const userReducer = (state = initialState, action) => {switch (action.type) {case 'LOGIN_REQUEST':return { ...state, isLoading: true, error: null };case 'LOGIN_SUCCESS':return { ...state, isLoading: false, currentUser: action.payload };case 'LOGIN_FAILURE':return { ...state, isLoading: false, error: action.payload };case 'LOGOUT':return { ...state, currentUser: null };default:return state;}
};// 用户 actions
export const loginUser = (credentials) => {return async (dispatch) => {try {dispatch({ type: 'LOGIN_REQUEST' });const response = await fetch('/api/auth/login', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify(credentials),});if (!response.ok) {const error = await response.json();throw new Error(error.message);}const data = await response.json();localStorage.setItem('token', data.token);dispatch({ type: 'LOGIN_SUCCESS', payload: data.user });} catch (error) {dispatch({ type: 'LOGIN_FAILURE', payload: error.message });}};
};

4.3 API 请求处理

使用 Axios 或 Fetch API 处理 HTTP 请求。

// 使用 Axios 的 API 服务
import axios from 'axios';// 创建 axios 实例
const apiClient = axios.create({baseURL: process.env.REACT_APP_API_URL,headers: {'Content-Type': 'application/json',},
});// 请求拦截器添加认证 token
apiClient.interceptors.request.use((config) => {const token = localStorage.getItem('token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;},(error) => {return Promise.reject(error);}
);// 响应拦截器处理错误
apiClient.interceptors.response.use((response) => response,(error) => {// 处理 401 错误if (error.response && error.response.status === 401) {// 清除本地存储并重定向到登录页localStorage.removeItem('token');window.location.href = '/login';}return Promise.reject(error);}
);// 用户相关 API 调用
export const userService = {login: (credentials) => apiClient.post('/auth/login', credentials),register: (userData) => apiClient.post('/auth/register', userData),getCurrentUser: () => apiClient.get('/users/me'),updateProfile: (userData) => apiClient.put('/users/me', userData),
};// 产品相关 API 调用
export const productService = {getProducts: (params) => apiClient.get('/products', { params }),getProductById: (id) => apiClient.get(`/products/${id}`),createProduct: (productData) => apiClient.post('/products', productData),updateProduct: (id, productData) => apiClient.put(`/products/${id}`, productData),deleteProduct: (id) => apiClient.delete(`/products/${id}`),
};export default apiClient;

4.4 前端路由 (React Router)

React Router 是 React 应用程序的声明式路由。

// React Router 配置
import React from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { useSelector } from 'react-redux';// 组件导入
import Home from './pages/Home';
import Login from './pages/Login';
import Register from './pages/Register';
import Dashboard from './pages/Dashboard';
import Profile from './pages/Profile';
import Products from './pages/Products';
import ProductDetail from './pages/ProductDetail';
import NotFound from './pages/NotFound';// 私有路由组件
const PrivateRoute = ({ children }) => {const { currentUser } = useSelector((state) => state.user);return currentUser ? children : <Navigate to="/login" />;
};const AppRouter = () => {return (<BrowserRouter><Routes><Route path="/" element={<Home />} /><Route path="/login" element={<Login />} /><Route path="/register" element={<Register />} />{/* 受保护的路由 */}<Route path="/dashboard" element={<PrivateRoute><Dashboard /></PrivateRoute>} /><Route path="/profile" element={<PrivateRoute><Profile /></PrivateRoute>} /><Route path="/products" element={<Products />} /><Route path="/products/:id" element={<ProductDetail />} />{/* 404 页面 */}<Route path="*" element={<NotFound />} /></Routes></BrowserRouter>);
};export default AppRouter;

4.5 前端架构

React 应用
组件层
状态管理层
服务层
路由层
工具层
页面组件
UI组件
布局组件
表单组件
Redux Store
Actions
Reducers
Middleware
API 服务
认证服务
存储服务
公共路由
私有路由
路由守卫
工具函数
自定义钩子
常量

5. 全栈集成

5.1 前后端通信

浏览器客户端 React 前端 Express API 数据库 用户操作 HTTP请求 发送JWT令牌进行身份验证 查询/操作数据 返回数据 JSON响应 包含状态码和数据 更新UI 浏览器客户端 React 前端 Express API 数据库

5.2 身份验证流程

用户 前端 (React) 后端 (Express) 数据库 输入登录凭据 POST /api/auth/login 验证用户凭据 返回用户数据 生成JWT令牌 返回令牌和用户信息 存储令牌(localStorage) 后续授权请求 发送请求(带Authorization头) 验证JWT令牌 返回受保护的资源 令牌过期 发送请求(带过期令牌) 返回401未授权 清除令牌并重定向到登录页 用户 前端 (React) 后端 (Express) 数据库

5.3 完整的全栈应用架构

基础设施
持久化层
数据层
API层
前端层
服务器 - AWS/Azure
CI/CD - Jenkins/GitHub Actions
监控 - Prometheus
日志 - ELK Stack
MongoDB/MySQL
文件存储
数据模型
数据访问对象
ORM - Mongoose/Sequelize
缓存 - Redis
Express 服务器
路由控制器
中间件
认证服务
业务逻辑
React 应用
状态管理 - Redux
路由 - React Router
UI库 - Material UI
API 客户端 - Axios

6. 数据建模与持久化

6.1 MongoDB 数据模型

// 用户模型
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');const userSchema = new mongoose.Schema({username: {type: String,required: true,unique: true,trim: true,minlength: 3,maxlength: 30,},email: {type: String,required: true,unique: true,trim: true,lowercase: true,match: [/^\S+@\S+\.\S+$/, '请提供有效的电子邮件地址'],},password: {type: String,required: true,minlength: 6,},role: {type: String,enum: ['user', 'admin'],default: 'user',},profilePicture: String,bio: {type: String,maxlength: 500,},isActive: {type: Boolean,default: true,},lastLogin: Date,
}, {timestamps: true,
});// 密码哈希中间件
userSchema.pre('save', async function(next) {if (!this.isModified('password')) return next();try {const salt = await bcrypt.genSalt(10);this.password = await bcrypt.hash(this.password, salt);next();} catch (error) {next(error);}
});// 验证密码方法
userSchema.methods.comparePassword = async function(candidatePassword) {return bcrypt.compare(candidatePassword, this.password);
};const User = mongoose.model('User', userSchema);module.exports = User;

6.2 MySQL 数据建模

-- 用户表
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(30) NOT NULL UNIQUE,email VARCHAR(100) NOT NULL UNIQUE,password VARCHAR(255) NOT NULL,role ENUM('user', 'admin') DEFAULT 'user',profile_picture VARCHAR(255),bio TEXT,is_active BOOLEAN DEFAULT TRUE,last_login DATETIME,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);-- 产品表
CREATE TABLE products (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,description TEXT,price DECIMAL(10, 2) NOT NULL,stock INT NOT NULL DEFAULT 0,category_id INT,image_url VARCHAR(255),is_featured BOOLEAN DEFAULT FALSE,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
);-- 类别表
CREATE TABLE categories (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL UNIQUE,description TEXT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);-- 订单表
CREATE TABLE orders (id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL,status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',total_amount DECIMAL(10, 2) NOT NULL,shipping_address TEXT NOT NULL,payment_method VARCHAR(50) NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);-- 订单项表
CREATE TABLE order_items (id INT AUTO_INCREMENT PRIMARY KEY,order_id INT NOT NULL,product_id INT NOT NULL,quantity INT NOT NULL,price DECIMAL(10, 2) NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
);-- 用户地址表
CREATE TABLE user_addresses (id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL,address_line1 VARCHAR(100) NOT NULL,address_line2 VARCHAR(100),city VARCHAR(50) NOT NULL,state VARCHAR(50) NOT NULL,postal_code VARCHAR(20) NOT NULL,country VARCHAR(50) NOT NULL,is_default BOOLEAN DEFAULT FALSE,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);-- 产品评论表
CREATE TABLE product_reviews (id INT AUTO_INCREMENT PRIMARY KEY,product_id INT NOT NULL,user_id INT NOT NULL,rating INT NOT NULL CHECK (rating BETWEEN 1 AND 5),comment TEXT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,UNIQUE (product_id, user_id)
);

6.3 数据关系建模

USERS int id PK string username string email string password enum role string profile_picture text bio boolean is_active datetime last_login timestamp created_at timestamp updated_at ORDERS int id PK int user_id FK enum status decimal total_amount text shipping_address string payment_method timestamp created_at timestamp updated_at USER_ADDRESSES int id PK int user_id FK string address_line1 string address_line2 string city string state string postal_code string country boolean is_default timestamp created_at timestamp updated_at PRODUCT_REVIEWS int id PK int product_id FK int user_id FK int rating text comment timestamp created_at timestamp updated_at CATEGORIES int id PK string name text description timestamp created_at timestamp updated_at PRODUCTS int id PK string name text description decimal price int stock int category_id FK string image_url boolean is_featured timestamp created_at timestamp updated_at ORDER_ITEMS int id PK int order_id FK int product_id FK int quantity decimal price timestamp created_at timestamp updated_at places has writes contains receives includes contains

7. API 开发与设计模式

7.1 模块化路由

// /routes/index.js - 路由主入口
const express = require('express');
const userRoutes = require('./userRoutes');
const productRoutes = require('./productRoutes');
const orderRoutes = require('./orderRoutes');
const authRoutes = require('./authRoutes');const router = express.Router();// API 版本控制
router.use('/v1/users', userRoutes);
router.use('/v1/products', productRoutes);
router.use('/v1/orders', orderRoutes);
router.use('/v1/auth', authRoutes);module.exports = router;// /routes/userRoutes.js - 用户相关路由
const express = require('express');
const userController = require('../controllers/userController');
const { authMiddleware, adminMiddleware } = require('../middleware/authMiddleware');const router = express.Router();// 公共路由
router.get('/:id/profile', userController.getUserProfile);// 需要认证的路由
router.get('/me', authMiddleware, userController.getCurrentUser);
router.put('/me', authMiddleware, userController.updateProfile);
router.get('/me/orders', authMiddleware, userController.getUserOrders);// 管理员路由
router.get('/', authMiddleware, adminMiddleware, userController.getAllUsers);
router.delete('/:id', authMiddleware, adminMiddleware, userController.deleteUser);module.exports = router;

7.2 控制器模式

// /controllers/productController.js
const Product = require('../models/Product');
const { createError } = require('../utils/errorHandler');// 控制器对象
const productController = {// 获取所有产品async getAllProducts(req, res, next) {try {const { category, search, minPrice, maxPrice, sort, limit = 10, page = 1 } = req.query;// 构建查询条件const query = {};if (category) {query.category_id = category;}if (search) {query.name = { $regex: search, $options: 'i' };}if (minPrice || maxPrice) {query.price = {};if (minPrice) query.price.$gte = parseFloat(minPrice);if (maxPrice) query.price.$lte = parseFloat(maxPrice);}// 构建排序条件let sortOptions = { createdAt: -1 }; // 默认按创建时间降序if (sort) {const [field, order] = sort.split(':');sortOptions = { [field]: order === 'desc' ? -1 : 1 };}// 计算分页const skip = (parseInt(page) - 1) * parseInt(limit);// 执行查询const products = await Product.find(query).sort(sortOptions).limit(parseInt(limit)).skip(skip);// 获取总数const total = await Product.countDocuments(query);res.json({products,pagination: {total,page: parseInt(page),limit: parseInt(limit),pages: Math.ceil(total / parseInt(limit)),},});} catch (error) {next(error);}},// 获取单个产品async getProductById(req, res, next) {try {const { id } = req.params;const product = await Product.findById(id);if (!product) {return next(createError(404, '找不到该产品'));}res.json(product);} catch (error) {next(error);}},// 创建产品async createProduct(req, res, next) {try {const productData = req.body;const newProduct = new Product(productData);await newProduct.save();res.status(201).json(newProduct);} catch (error) {next(error);}},// 更新产品async updateProduct(req, res, next) {try {const { id } = req.params;const updateData = req.body;const product = await Product.findByIdAndUpdate(id,updateData,{ new: true, runValidators: true });if (!product) {return next(createError(404, '找不到该产品'));}res.json(product);} catch (error) {next(error);}},// 删除产品async deleteProduct(req, res, next) {try {const { id } = req.params;const product = await Product.findByIdAndDelete(id);if (!product) {return next(createError(404, '找不到该产品'));}res.status(204).end();} catch (error) {next(error);}},
};module.exports = productController;

7.3 服务层模式

// /services/orderService.js
const Order = require('../models/Order');
const Product = require('../models/Product');
const { createError } = require('../utils/errorHandler');// 订单服务
const orderService = {// 创建订单async createOrder(orderData, userId) {// 验证产品库存const orderItems = orderData.items;let totalAmount = 0;// 验证所有产品是否有足够库存for (const item of orderItems) {const product = await Product.findById(item.productId);if (!product) {throw createError(404, `商品ID ${item.productId} 不存在`);}if (product.stock < item.quantity) {throw createError(400, `商品 ${product.name} 库存不足`);}// 计算项目价格item.price = product.price;totalAmount += product.price * item.quantity;}// 创建订单事务const session = await Order.startSession();session.startTransaction();try {// 创建订单const newOrder = new Order({user: userId,items: orderItems.map(item => ({product: item.productId,quantity: item.quantity,price: item.price})),totalAmount,shippingAddress: orderData.shippingAddress,paymentMethod: orderData.paymentMethod,status: 'pending'});await newOrder.save({ session });// 更新产品库存for (const item of orderItems) {await Product.findByIdAndUpdate(item.productId,{ $inc: { stock: -item.quantity } },{ session });}// 提交事务await session.commitTransaction();session.endSession();return newOrder;} catch (error) {// 回滚事务await session.abortTransaction();session.endSession();throw error;}},// 获取用户订单async getUserOrders(userId) {return Order.find({ user: userId }).sort({ createdAt: -1 }).populate('items.product', 'name image_url');},// 获取订单详情async getOrderById(orderId, userId, isAdmin = false) {const query = { _id: orderId };// 如果不是管理员,只能查看自己的订单if (!isAdmin) {query.user = userId;}const order = await Order.findOne(query).populate('user', 'username email').populate('items.product');if (!order) {throw createError(404, '订单不存在');}return order;},// 更新订单状态async updateOrderStatus(orderId, status, userId, isAdmin = false) {const query = { _id: orderId };// 如果不是管理员,只能更新自己的订单if (!isAdmin) {query.user = userId;// 非管理员只能取消订单if (status !== 'cancelled') {throw createError(403, '没有权限执行此操作');}// 只能取消待处理或处理中的订单query.status = { $in: ['pending', 'processing'] };}const order = await Order.findOneAndUpdate(query,{ status },{ new: true, runValidators: true });if (!order) {throw createError(404, '订单不存在或无法更新状态');}return order;},
};module.exports = orderService;

7.4 错误处理模式

// /utils/errorHandler.js
// 创建自定义错误
const createError = (statusCode, message, details = null) => {const error = new Error(message);error.statusCode = statusCode;error.details = details;return error;
};// 全局错误处理中间件
const errorHandler = (err, req, res, next) => {console.error('Error:', err);// 获取错误状态码和消息const statusCode = err.statusCode || 500;const message = err.message || '服务器内部错误';// 区分不同环境下的错误响应const response = {error: {message,status: statusCode,},};// 在开发环境中提供更详细的错误信息if (process.env.NODE_ENV === 'development') {response.error.stack = err.stack;if (err.details) {response.error.details = err.details;}}// MongoDB 验证错误处理if (err.name === 'ValidationError') {response.error.status = 400;response.error.message = '数据验证失败';response.error.details = Object.values(err.errors).map(e => e.message);}// MongoDB 重复键错误处理if (err.code === 11000) {response.error.status = 409;response.error.message = '数据已存在';const field = Object.keys(err.keyValue)[0];response.error.details = `${field} 已被使用`;}// JWT 错误处理if (err.name === 'JsonWebTokenError') {response.error.status = 401;response.error.message = '无效的认证令牌';}if (err.name === 'TokenExpiredError') {response.error.status = 401;response.error.message = '认证令牌已过期';}res.status(response.error.status).json(response);
};module.exports = { createError, errorHandler };

8. 安全性与性能优化

8.1 安全最佳实践

// /config/security.js
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');
const cors = require('cors');// 配置安全中间件
const configSecurity = (app) => {// 设置安全 HTTP 头app.use(helmet());// 防止 XSS 攻击app.use(xss());// 防止 NoSQL 注入app.use(mongoSanitize());// 防止参数污染app.use(hpp());// 配置 CORSapp.use(cors({origin: process.env.CORS_ORIGIN || '*',methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],allowedHeaders: ['Content-Type', 'Authorization'],credentials: true,}));// 配置速率限制const limiter = rateLimit({windowMs: 15 * 60 * 1000, // 15分钟max: 100, // 每个IP在windowMs内最多100个请求message: {error: {message: '请求过多,请稍后再试',status: 429,},},});// 应用速率限制到所有请求app.use('/api', limiter);// 严格的认证路由限制const authLimiter = rateLimit({windowMs: 60 * 60 * 1000, // 1小时max: 10, // 每个IP每小时最多10次尝试message: {error: {message: '尝试次数过多,请稍后再试',status: 429,},},});// 应用认证限制到登录和注册路由app.use('/api/v1/auth/login', authLimiter);app.use('/api/v1/auth/register', authLimiter);
};module.exports = configSecurity;

8.2 性能优化技术

// /config/performance.js
const compression = require('compression');
const { createClient } = require('redis');// Redis 客户端
let redisClient;// 配置性能优化
const configPerformance = async (app) => {// 启用 gzip 压缩app.use(compression());// 设置 Redis 缓存(如果配置了)if (process.env.REDIS_URL) {redisClient = createClient({url: process.env.REDIS_URL,});await redisClient.connect().catch(err => {console.error('Redis 连接失败:', err);});redisClient.on('error', (err) => {console.error('Redis 错误:', err);});console.log('Redis 缓存已启用');}
};// 缓存中间件
const cacheMiddleware = (duration) => {return async (req, res, next) => {// 如果 Redis 未连接,跳过缓存if (!redisClient || !redisClient.isReady) {return next();}// 跳过非 GET 请求的缓存if (req.method !== 'GET') {return next();}// 创建缓存键const cacheKey = `api:${req.originalUrl}`;try {// 尝试从缓存获取数据const cachedData = await redisClient.get(cacheKey);if (cachedData) {// 返回缓存数据const data = JSON.parse(cachedData);return res.json(data);}// 修改 res.json 方法以缓存响应const originalJson = res.json;res.json = function(data) {// 将数据保存到缓存redisClient.setEx(cacheKey, duration, JSON.stringify(data)).catch(err => console.error('Redis 缓存错误:', err));// 调用原始 json 方法return originalJson.call(this, data);};next();} catch (error) {console.error('缓存错误:', error);next();}};
};// 清除缓存模式
const clearCache = async (pattern) => {if (!redisClient || !redisClient.isReady) {return;}try {// 查找匹配的键const keys = await redisClient.keys(pattern);// 如果有匹配的键,删除它们if (keys.length > 0) {await redisClient.del(keys);console.log(`已清除 ${keys.length} 个缓存键`);}} catch (error) {console.error('清除缓存错误:', error);}
};module.exports = {configPerformance,cacheMiddleware,clearCache,
};

8.3 日志系统

// /utils/logger.js
const winston = require('winston');
const { format, transports, createLogger } = winston;
const path = require('path');// 定义日志格式
const logFormat = format.combine(format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),format.errors({ stack: true }),format.splat(),format.json()
);// 创建 logger 实例
const logger = createLogger({level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',format: logFormat,defaultMeta: { service: 'api-service' },transports: [// 控制台输出new transports.Console({format: format.combine(format.colorize(),format.printf(info => `${info.timestamp} ${info.level}: ${info.message}${info.stack ? '\n' + info.stack : ''}`)),}),],
});// 在生产环境中添加文件传输
if (process.env.NODE_ENV === 'production') {logger.add(new transports.File({filename: path.join(__dirname, '../logs/error.log'),level: 'error',maxsize: 10485760, // 10MBmaxFiles: 5,}));logger.add(new transports.File({filename: path.join(__dirname, '../logs/combined.log'),maxsize: 10485760, // 10MBmaxFiles: 5,}));
}// 捕获未处理的异常和拒绝
logger.exceptions.handle(new transports.File({ filename: path.join(__dirname, '../logs/exceptions.log') })
);// 中间件:请求日志
const requestLogger = (req, res, next) => {const startTime = new Date();// 请求完成时的回调res.on('finish', () => {const duration = new Date() - startTime;logger.info({type: 'request',method: req.method,path: req.path,query: req.query,statusCode: res.statusCode,duration: `${duration}ms`,userAgent: req.get('User-Agent'),ip: req.ip,});});next();
};module.exports = { logger, requestLogger };

9. 部署与 DevOps

9.1 Docker 容器化

# Dockerfile
FROM node:18-alpine# 创建应用目录
WORKDIR /usr/src/app# 安装应用依赖
COPY package*.json ./
RUN npm ci --only=production# 复制应用代码
COPY . .# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000# 暴露端口
EXPOSE 3000# 启动应用
CMD ["node", "server.js"]
# docker-compose.yml
version: '3'services:app:build: .restart: alwaysports:- "3000:3000"depends_on:- mongodb- redisenvironment:- NODE_ENV=production- PORT=3000- MONGODB_URI=mongodb://mongodb:27017/myapp- REDIS_URL=redis://redis:6379- JWT_SECRET=your_jwt_secret- CORS_ORIGIN=https://yourdomain.comvolumes:- ./logs:/usr/src/app/logsnetworks:- app-networkmongodb:image: mongo:6restart: alwaysports:- "27017:27017"volumes:- mongodb-data:/data/dbnetworks:- app-networkredis:image: redis:7-alpinerestart: alwaysports:- "6379:6379"volumes:- redis-data:/datanetworks:- app-networknetworks:app-network:driver: bridgevolumes:mongodb-data:redis-data:

9.2 CI/CD 流水线

# .github/workflows/main.yml
name: Node.js CI/CDon:push:branches: [ main ]pull_request:branches: [ main ]jobs:test:runs-on: ubuntu-lateststrategy:matrix:node-version: [16.x, 18.x]steps:- uses: actions/checkout@v3- name: Use Node.js ${{ matrix.node-version }}uses: actions/setup-node@v3with:node-version: ${{ matrix.node-version }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Run lintingrun: npm run lint- name: Run testsrun: npm testbuild-and-deploy:needs: testruns-on: ubuntu-latestif: github.event_name == 'push' && github.ref == 'refs/heads/main'steps:- uses: actions/checkout@v3- name: Use Node.js 18.xuses: actions/setup-node@v3with:node-version: 18.xcache: 'npm'- name: Install dependenciesrun: npm ci- name: Buildrun: npm run build- name: Set up Docker Buildxuses: docker/setup-buildx-action@v2- name: Login to DockerHubuses: docker/login-action@v2with:username: ${{ secrets.DOCKERHUB_USERNAME }}password: ${{ secrets.DOCKERHUB_TOKEN }}- name: Build and push Docker imageuses: docker/build-push-action@v4with:context: .push: truetags: yourusername/yourapp:latest- name: Deploy to serveruses: appleboy/ssh-action@masterwith:host: ${{ secrets.SSH_HOST }}username: ${{ secrets.SSH_USERNAME }}key: ${{ secrets.SSH_PRIVATE_KEY }}script: |cd /path/to/your/appdocker-compose pulldocker-compose up -d

9.3 部署流程

代码提交
自动化测试
失败
成功
失败
成功
开发阶段
CI/CD 流水线
测试通过?
通知开发者
构建 Docker 镜像
推送到容器仓库
部署到测试环境
性能和验收测试
部署到生产环境
监控系统性能
发现问题?
回滚部署
完成部署

结语
感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词