Appearance
第14章:Node.js 进阶技巧(提升效率)
14.1 环境变量配置(.env文件,区分开发/生产环境)
为什么需要环境变量
- 区分开发、测试、生产环境的配置
- 存储敏感信息(如数据库密码、API密钥)
- 避免硬编码配置信息
实现方法
安装 dotenv 包:
bashnpm install dotenv创建 .env 文件:
txt# 开发环境 NODE_ENV=development PORT=3000 DB_HOST=localhost DB_USER=root DB_PASSWORD=password DB_NAME=todo_list # API密钥 API_KEY=your_api_key在应用中加载环境变量:
javascriptrequire('dotenv').config(); const port = process.env.PORT || 3000; const dbConfig = { host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME };添加 .env 到 .gitignore:
# 环境变量文件 .env
14.2 错误处理进阶(全局错误捕获、接口异常处理)
全局错误处理中间件
javascript
// 全局错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
// 区分错误类型
if (err.name === 'ValidationError') {
return res.status(400).json({ error: err.message });
}
if (err.code === 'ECONNREFUSED') {
return res.status(503).json({ error: 'Database connection failed' });
}
// 默认500错误
res.status(500).json({ error: 'Internal server error' });
});异步错误捕获
javascript
// 异步错误捕获中间件
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// 使用
app.get('/api/users', asyncHandler(async (req, res) => {
const users = await User.find();
res.json(users);
}));自定义错误类
javascript
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = statusCode >= 400 && statusCode < 500 ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
// 使用
if (!user) {
throw new AppError('User not found', 404);
}14.3 中间件封装(通用中间件:日志、权限验证)
日志中间件
javascript
const logger = (req, res, next) => {
const start = Date.now();
// 记录请求信息
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
// 监听响应结束
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url} ${res.statusCode} ${duration}ms`);
});
next();
};
app.use(logger);权限验证中间件
javascript
const auth = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid token' });
}
};
// 保护路由
app.get('/api/profile', auth, (req, res) => {
res.json({ user: req.user });
});CORS 中间件
javascript
const cors = (req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
next();
};
app.use(cors);14.4 Node.js 性能优化基础(减少阻塞、合理使用异步)
减少阻塞操作
使用异步API:
- 优先使用异步版本的文件操作、数据库查询等
- 避免在主线程中执行CPU密集型任务
使用工作线程:
javascriptconst { Worker, isMainThread, parentPort } = require('worker_threads'); if (isMainThread) { // 主线程 const worker = new Worker(__filename); worker.on('message', result => { console.log('Result:', result); }); worker.postMessage({ number: 1000000 }); } else { // 工作线程 parentPort.on('message', ({ number }) => { // 执行CPU密集型任务 let result = 0; for (let i = 0; i < number; i++) { result += i; } parentPort.postMessage(result); }); }
合理使用异步
并行处理:
javascript// 串行处理 async function serial() { const result1 = await fetch('https://api.example.com/data1'); const result2 = await fetch('https://api.example.com/data2'); return [result1, result2]; } // 并行处理 async function parallel() { const [result1, result2] = await Promise.all([ fetch('https://api.example.com/data1'), fetch('https://api.example.com/data2') ]); return [result1, result2]; }使用缓存:
javascriptconst cache = new Map(); async function getData(key) { if (cache.has(key)) { return cache.get(key); } const data = await fetchDataFromDatabase(key); cache.set(key, data); return data; }
优化数据库操作
使用连接池:
javascriptconst mysql = require('mysql2'); const pool = mysql.createPool({ host: 'localhost', user: 'root', password: 'password', database: 'test', waitForConnections: true, connectionLimit: 10, queueLimit: 0 });批量操作:
javascript// 批量插入 const users = [ { name: 'User1', email: 'user1@example.com' }, { name: 'User2', email: 'user2@example.com' } ]; const query = 'INSERT INTO users (name, email) VALUES ?'; const values = users.map(user => [user.name, user.email]); pool.query(query, [values], (err, results) => { if (err) throw err; console.log('Inserted', results.affectedRows, 'rows'); });
14.5 其他常用框架简介(Koa、Nest.js,了解即可)
Koa
- 特点:由 Express 团队开发,更轻量、更现代
- 核心特性:
- 基于 async/await 的中间件机制
- 内置上下文对象(ctx)
- 错误处理更优雅
- 示例:javascript
const Koa = require('koa'); const app = new Koa(); app.use(async (ctx) => { ctx.body = 'Hello Koa'; }); app.listen(3000);
Nest.js
- 特点:基于 TypeScript,企业级框架
- 核心特性:
- 依赖注入
- 模块化架构
- 支持 GraphQL
- 内置中间件、守卫、管道等
- 示例:typescript
import { Controller, Get, Module } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; @Controller() class AppController { @Get() getHello(): string { return 'Hello Nest.js'; } } @Module({ controllers: [AppController], }) class AppModule {} async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();
选择建议
- Express:适合快速开发、中小型项目
- Koa:适合追求简洁、现代的项目
- Nest.js:适合大型企业级应用、需要严格架构的项目
