Node.js后端开发完整指南

从零开始学习Node.js后端开发,包括Express框架、数据库操作、API设计、身份验证等核心知识点。

Node.js让JavaScript不再局限于浏览器,成为了全栈开发的强大工具。今天分享Node.js后端开发的完整学习路径。

🚀 Node.js基础

什么是Node.js

Node.js是一个基于Chrome V8引擎的JavaScript运行环境,让JavaScript能够在服务器端运行。

核心特性

  • 🔄 事件驱动:非阻塞I/O模型
  • 高性能:适合I/O密集型应用
  • 📦 NPM生态:丰富的第三方包
  • 🌐 跨平台:Windows、macOS、Linux

环境搭建

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 安装Node.js(推荐使用nvm管理版本)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install node
nvm use node

# 验证安装
node --version
npm --version

# 创建项目
mkdir my-node-app
cd my-node-app
npm init -y

📊 Express框架入门

快速开始

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const express = require('express');
const app = express();
const port = 3000;

// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 路由
app.get('/', (req, res) => {
    res.json({ message: 'Hello World!' });
});

app.listen(port, () => {
    console.log(`服务器运行在 http://localhost:${port}`);
});

中间件系统

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 日志中间件
const logger = (req, res, next) => {
    console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
    next();
};

// 错误处理中间件
const errorHandler = (err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({ error: 'Something went wrong!' });
};

// 应用中间件
app.use(logger);
app.use('/api', apiRoutes);
app.use(errorHandler);

路由设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
const router = express.Router();

// RESTful API设计
router.get('/users', getAllUsers);           // 获取所有用户
router.get('/users/:id', getUserById);       // 获取单个用户
router.post('/users', createUser);           // 创建用户
router.put('/users/:id', updateUser);        // 更新用户
router.delete('/users/:id', deleteUser);     // 删除用户

// 路由处理函数
const getAllUsers = async (req, res) => {
    try {
        const users = await User.find();
        res.json(users);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
};

module.exports = router;

🗄️ 数据库集成

MongoDB + Mongoose

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const mongoose = require('mongoose');

// 连接数据库
mongoose.connect('mongodb://localhost:27017/myapp', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

// 定义Schema
const userSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        trim: true
    },
    email: {
        type: String,
        required: true,
        unique: true,
        lowercase: true
    },
    password: {
        type: String,
        required: true,
        minlength: 6
    },
    createdAt: {
        type: Date,
        default: Date.now
    }
});

// 密码加密中间件
userSchema.pre('save', async function(next) {
    if (!this.isModified('password')) return next();
    
    const bcrypt = require('bcrypt');
    this.password = await bcrypt.hash(this.password, 12);
    next();
});

const User = mongoose.model('User', userSchema);

数据库操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 创建用户
const createUser = async (userData) => {
    try {
        const user = new User(userData);
        await user.save();
        return user;
    } catch (error) {
        throw error;
    }
};

// 查询用户
const findUsers = async (filter = {}) => {
    return await User.find(filter)
        .select('-password')
        .sort({ createdAt: -1 });
};

// 更新用户
const updateUser = async (id, updateData) => {
    return await User.findByIdAndUpdate(
        id, 
        updateData, 
        { new: true, runValidators: true }
    );
};

🔐 身份验证与授权

JWT身份验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

// 生成JWT Token
const generateToken = (userId) => {
    return jwt.sign({ userId }, process.env.JWT_SECRET, {
        expiresIn: '7d'
    });
};

// 登录功能
const login = async (req, res) => {
    try {
        const { email, password } = req.body;
        
        // 查找用户
        const user = await User.findOne({ email });
        if (!user) {
            return res.status(401).json({ error: '邮箱或密码错误' });
        }
        
        // 验证密码
        const isMatch = await bcrypt.compare(password, user.password);
        if (!isMatch) {
            return res.status(401).json({ error: '邮箱或密码错误' });
        }
        
        // 生成token
        const token = generateToken(user._id);
        
        res.json({
            message: '登录成功',
            token,
            user: {
                id: user._id,
                name: user.name,
                email: user.email
            }
        });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
};

认证中间件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const authenticate = async (req, res, next) => {
    try {
        const token = req.header('Authorization')?.replace('Bearer ', '');
        
        if (!token) {
            return res.status(401).json({ error: '访问被拒绝,需要token' });
        }
        
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        const user = await User.findById(decoded.userId);
        
        if (!user) {
            return res.status(401).json({ error: '用户不存在' });
        }
        
        req.user = user;
        next();
    } catch (error) {
        res.status(401).json({ error: 'Token无效' });
    }
};

// 使用认证中间件
app.use('/api/protected', authenticate);

📝 API设计最佳实践

RESTful API规范

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 统一响应格式
const sendResponse = (res, statusCode, data, message) => {
    res.status(statusCode).json({
        success: statusCode < 400,
        message,
        data,
        timestamp: new Date().toISOString()
    });
};

// API版本控制
app.use('/api/v1', v1Routes);
app.use('/api/v2', v2Routes);

// 参数验证中间件
const validateUser = (req, res, next) => {
    const { name, email, password } = req.body;
    
    if (!name || !email || !password) {
        return sendResponse(res, 400, null, '缺少必要参数');
    }
    
    if (password.length < 6) {
        return sendResponse(res, 400, null, '密码长度至少6位');
    }
    
    next();
};

分页和排序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const getPaginatedUsers = async (req, res) => {
    try {
        const page = parseInt(req.query.page) || 1;
        const limit = parseInt(req.query.limit) || 10;
        const sort = req.query.sort || 'createdAt';
        const order = req.query.order === 'asc' ? 1 : -1;
        
        const skip = (page - 1) * limit;
        
        const users = await User.find()
            .select('-password')
            .sort({ [sort]: order })
            .skip(skip)
            .limit(limit);
            
        const total = await User.countDocuments();
        
        res.json({
            users,
            pagination: {
                currentPage: page,
                totalPages: Math.ceil(total / limit),
                totalItems: total,
                itemsPerPage: limit
            }
        });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
};

🔧 实用工具和中间件

环境配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// .env文件
const dotenv = require('dotenv');
dotenv.config();

// config/database.js
module.exports = {
    development: {
        url: process.env.DEV_DB_URL,
        options: {
            useNewUrlParser: true,
            useUnifiedTopology: true
        }
    },
    production: {
        url: process.env.PROD_DB_URL,
        options: {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            ssl: true
        }
    }
};

文件上传

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const multer = require('multer');
const path = require('path');

// 配置存储
const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'uploads/');
    },
    filename: (req, file, cb) => {
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
    }
});

const upload = multer({
    storage,
    limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
    fileFilter: (req, file, cb) => {
        const allowedTypes = /jpeg|jpg|png|gif/;
        const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
        const mimetype = allowedTypes.test(file.mimetype);
        
        if (mimetype && extname) {
            return cb(null, true);
        } else {
            cb(new Error('只允许上传图片文件'));
        }
    }
});

// 使用文件上传
app.post('/api/upload', upload.single('image'), (req, res) => {
    if (!req.file) {
        return res.status(400).json({ error: '没有文件上传' });
    }
    
    res.json({
        message: '文件上传成功',
        filename: req.file.filename,
        path: req.file.path
    });
});

日志系统

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const winston = require('winston');

const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.errors({ stack: true }),
        winston.format.json()
    ),
    transports: [
        new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
        new winston.transports.File({ filename: 'logs/combined.log' })
    ]
});

if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

module.exports = logger;

🧪 测试

单元测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const request = require('supertest');
const app = require('../app');

describe('User API', () => {
    describe('POST /api/users', () => {
        it('should create a new user', async () => {
            const userData = {
                name: 'Test User',
                email: 'test@example.com',
                password: 'password123'
            };
            
            const response = await request(app)
                .post('/api/users')
                .send(userData)
                .expect(201);
                
            expect(response.body.user.name).toBe(userData.name);
            expect(response.body.user.email).toBe(userData.email);
        });
        
        it('should return 400 if required fields are missing', async () => {
            const response = await request(app)
                .post('/api/users')
                .send({})
                .expect(400);
                
            expect(response.body.success).toBe(false);
        });
    });
});

🚀 部署和优化

PM2进程管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 安装PM2
npm install -g pm2

# 启动应用
pm2 start app.js --name "my-app"

# 集群模式
pm2 start app.js -i max

# 监控
pm2 monitor

# 日志查看
pm2 logs

性能优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 启用gzip压缩
const compression = require('compression');
app.use(compression());

// 设置安全headers
const helmet = require('helmet');
app.use(helmet());

// 限制请求频率
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 100 // 限制每个IP 100次请求
});
app.use(limiter);

// 缓存
const redis = require('redis');
const client = redis.createClient();

const cache = (duration) => {
    return async (req, res, next) => {
        const key = req.originalUrl;
        const cached = await client.get(key);
        
        if (cached) {
            return res.json(JSON.parse(cached));
        }
        
        res.sendResponse = res.json;
        res.json = (body) => {
            client.setex(key, duration, JSON.stringify(body));
            res.sendResponse(body);
        };
        
        next();
    };
};

📊 推荐学习资源

📚 书籍推荐

  • 《Node.js实战》 - 全面的Node.js指南
  • 《深入浅出Node.js》 - 朴灵著,深入理解Node.js原理

🔧 实用工具

  • Postman - API测试工具
  • MongoDB Compass - 可视化数据库管理
  • VS Code - 最佳Node.js开发环境

📦 常用包推荐

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^6.8.0",
    "bcrypt": "^5.1.0",
    "jsonwebtoken": "^8.5.1",
    "dotenv": "^16.0.3",
    "cors": "^2.8.5",
    "helmet": "^6.0.1",
    "compression": "^1.7.4"
  },
  "devDependencies": {
    "nodemon": "^2.0.20",
    "jest": "^29.3.1",
    "supertest": "^6.3.3"
  }
}

💡 总结

Node.js后端开发的核心要点:

  1. 掌握基础概念 - 事件循环、模块系统、异步编程
  2. 熟练使用Express - 路由、中间件、错误处理
  3. 数据库操作 - MongoDB/MySQL + ORM/ODM
  4. 身份验证 - JWT、Session、OAuth
  5. API设计 - RESTful、GraphQL
  6. 测试和部署 - 单元测试、集成测试、CI/CD

记住,后端开发不只是写代码,还要考虑安全性、性能、可维护性等方面。持续学习,关注最新技术动态!


你在Node.js开发中遇到过哪些挑战?欢迎在评论区分享经验!