02-Express框架
Express是Node.js最流行的Web框架,简洁灵活,中间件机制强大。
基础使用
安装和启动
npm install express
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello Express!');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
路由
// GET请求
app.get('/users', (req, res) => {
res.json({ users: [] });
});
// POST请求
app.post('/users', (req, res) => {
res.status(201).json({ message: 'Created' });
});
// PUT请求
app.put('/users/:id', (req, res) => {
const { id } = req.params;
res.json({ message: `Updated user ${id}` });
});
// DELETE请求
app.delete('/users/:id', (req, res) => {
res.status(204).send();
});
// 路由参数
app.get('/users/:id', (req, res) => {
const { id } = req.params;
res.json({ id });
});
// 多个参数
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.json({ userId, postId });
});
// 查询参数
app.get('/search', (req, res) => {
const { q, page = 1, limit = 10 } = req.query;
res.json({ q, page, limit });
// /search?q=keyword&page=2&limit=20
});
// 正则路由
app.get(/.*fly$/, (req, res) => {
res.send('ends with fly');
});
Router模块化
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.json({ users: [] });
});
router.post('/', (req, res) => {
res.status(201).json({ message: 'Created' });
});
router.get('/:id', (req, res) => {
res.json({ id: req.params.id });
});
module.exports = router;
// app.js
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);
// GET /api/users → router.get('/')
// GET /api/users/123 → router.get('/:id')
中间件
内置中间件
// 解析JSON请求体
app.use(express.json());
// 解析URL编码数据
app.use(express.urlencoded({ extended: true }));
// 静态文件
app.use(express.static('public'));
app.use('/static', express.static('public'));
自定义中间件
// 日志中间件
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // 调用下一个中间件
};
app.use(logger);
// 认证中间件
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
}
// 验证token
try {
const user = verifyToken(token);
req.user = user; // 添加到req对象
next();
} catch (err) {
res.status(401).json({ error: 'Invalid token' });
}
};
// 应用到特定路由
app.get('/protected', authMiddleware, (req, res) => {
res.json({ user: req.user });
});
// 错误处理中间件(4个参数)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
第三方中间件
// morgan:日志
const morgan = require('morgan');
app.use(morgan('combined'));
// cors:跨域
const cors = require('cors');
app.use(cors());
// helmet:安全头
const helmet = require('helmet');
app.use(helmet());
// compression:压缩
const compression = require('compression');
app.use(compression());
// express-validator:验证
const { body, validationResult } = require('express-validator');
app.post('/users',
body('email').isEmail(),
body('password').isLength({ min: 6 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 处理请求
}
);
请求和响应
Request对象
app.get('/api/data', (req, res) => {
// 查询参数
const { page, limit } = req.query;
// 路由参数
const { id } = req.params;
// 请求体
const { name, email } = req.body;
// 请求头
const token = req.get('Authorization');
const userAgent = req.get('User-Agent');
// 其他属性
console.log(req.method); // GET
console.log(req.url); // /api/data?page=1
console.log(req.path); // /api/data
console.log(req.hostname); // example.com
console.log(req.ip); // 客户端IP
console.log(req.protocol); // http/https
});
Response对象
app.get('/api/data', (req, res) => {
// 发送文本
res.send('Hello');
// 发送JSON
res.json({ message: 'Success' });
// 设置状态码
res.status(404).send('Not Found');
res.status(201).json({ message: 'Created' });
// 设置响应头
res.set('Content-Type', 'application/json');
res.set({
'Content-Type': 'text/html',
'X-Custom-Header': 'value'
});
// 重定向
res.redirect('/new-url');
res.redirect(301, '/permanent-redirect');
// 发送文件
res.sendFile('/path/to/file.pdf');
// 下载文件
res.download('/path/to/file.pdf', 'filename.pdf');
// 渲染模板
res.render('index', { title: 'Home' });
});
模板引擎
EJS
npm install ejs
// 设置模板引擎
app.set('view engine', 'ejs');
app.set('views', './views');
// 渲染
app.get('/', (req, res) => {
res.render('index', {
title: 'Home',
users: ['Alice', 'Bob']
});
});
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<ul>
<% users.forEach(user => { %>
<li><%= user %></li>
<% }); %>
</ul>
</body>
</html>
Pug(原Jade)
npm install pug
app.set('view engine', 'pug');
//- views/index.pug
doctype html
html
head
title= title
body
h1= title
ul
each user in users
li= user
RESTful API示例
const express = require('express');
const app = express();
app.use(express.json());
// 模拟数据库
let users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
];
// GET /api/users
app.get('/api/users', (req, res) => {
res.json(users);
});
// GET /api/users/:id
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
// POST /api/users
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
const newUser = {
id: users.length + 1,
name,
email
};
users.push(newUser);
res.status(201).json(newUser);
});
// PUT /api/users/:id
app.put('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const { name, email } = req.body;
user.name = name || user.name;
user.email = email || user.email;
res.json(user);
});
// DELETE /api/users/:id
app.delete('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: 'User not found' });
}
users.splice(index, 1);
res.status(204).send();
});
app.listen(3000);
错误处理
同步错误
app.get('/sync-error', (req, res) => {
throw new Error('Sync error'); // 自动捕获
});
异步错误
// ❌ 错误:异步错误未捕获
app.get('/async-error', (req, res) => {
setTimeout(() => {
throw new Error('Async error'); // 不会被捕获
}, 100);
});
// ✅ 正确:使用next
app.get('/async-error', (req, res, next) => {
setTimeout(() => {
next(new Error('Async error'));
}, 100);
});
// ✅ Promise错误
app.get('/promise-error', (req, res, next) => {
doAsyncWork()
.then(result => res.json(result))
.catch(next); // 传递给错误处理中间件
});
// ✅ async/await
app.get('/async-await', async (req, res, next) => {
try {
const result = await doAsyncWork();
res.json(result);
} catch (err) {
next(err);
}
});
// 或使用包装器
const asyncHandler = fn => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.get('/users', asyncHandler(async (req, res) => {
const users = await User.find();
res.json(users);
}));
错误处理中间件
// 404处理
app.use((req, res, next) => {
res.status(404).json({ error: 'Not Found' });
});
// 错误处理(放在所有路由后)
app.use((err, req, res, next) => {
console.error(err.stack);
// 根据环境返回错误详情
const errorResponse = {
error: err.message
};
if (process.env.NODE_ENV === 'development') {
errorResponse.stack = err.stack;
}
res.status(err.status || 500).json(errorResponse);
});
最佳实践
项目结构
src/
├── app.js # Express应用配置
├── server.js # 服务器启动
├── routes/ # 路由
│ ├── index.js
│ ├── users.js
│ └── posts.js
├── controllers/ # 控制器
│ ├── userController.js
│ └── postController.js
├── models/ # 数据模型
│ ├── User.js
│ └── Post.js
├── middlewares/ # 中间件
│ ├── auth.js
│ ├── validator.js
│ └── errorHandler.js
├── services/ # 业务逻辑
│ └── userService.js
├── utils/ # 工具函数
│ └── logger.js
└── config/ # 配置
└── database.js
环境配置
// config/config.js
module.exports = {
development: {
port: 3000,
db: {
host: 'localhost',
port: 27017,
name: 'myapp_dev'
}
},
production: {
port: process.env.PORT || 8080,
db: {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
name: process.env.DB_NAME
}
}
};
const env = process.env.NODE_ENV || 'development';
const config = require('./config')[env];
路由控制器分离
// controllers/userController.js
exports.getUsers = async (req, res, next) => {
try {
const users = await User.find();
res.json(users);
} catch (err) {
next(err);
}
};
exports.createUser = async (req, res, next) => {
try {
const user = await User.create(req.body);
res.status(201).json(user);
} catch (err) {
next(err);
}
};
// routes/users.js
const router = require('express').Router();
const controller = require('../controllers/userController');
router.get('/', controller.getUsers);
router.post('/', controller.createUser);
module.exports = router;
核心: Express通过中间件机制构建灵活Web应用,路由清晰,扩展性强。