最完整Express.js入门指南:从零构建Node.js应用
【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express
引言:为什么选择Express.js?
你是否还在为选择合适的Node.js Web框架而困惑?是否想要快速构建高性能的Web应用但不知从何入手?本文将带你从零开始掌握Express.js(版本4.19.2),这个被称为"Fast, unopinionated, minimalist web framework"的轻量级框架,帮助你构建生产级别的Node.js应用。
Express.js作为Node.js生态中最受欢迎的Web框架之一,具有以下优势:
- 极简设计,灵活高效
- 强大的路由系统和中间件支持
- 丰富的生态系统和社区支持
- 与各种模板引擎和数据库无缝集成
通过本文,你将学习到:
- Express.js的核心概念与架构
- 环境搭建与项目初始化
- 路由设计与中间件使用
- 模板引擎与静态资源管理
- 错误处理与性能优化
- 从零构建一个完整的MVC应用
Express.js基础架构解析
Express.js的核心组件
Express.js的核心架构由以下几个关键部分组成:
核心组件说明:
- Application(应用):Express应用的入口点,通过
express()创建,负责全局配置和中间件管理 - Router(路由器):负责请求的路由分发,可创建多个独立的路由器
- Route(路由):定义特定HTTP方法和路径的处理逻辑
- Layer(层):封装中间件和路由处理器,构成处理管道
Express.js请求处理流程
当一个请求到达Express应用时,会经过以下处理流程:
环境搭建与项目初始化
安装Node.js和npm
Express.js需要Node.js环境,建议安装Node.js v14.x或更高版本。可以通过以下命令检查Node.js和npm是否已安装:
node -v
npm -v
如果需要使用国内npm镜像以提高下载速度,可以执行:
npm config set registry https://registry.npmmirror.com
创建Express项目
有两种方式可以创建Express项目:使用Express生成器或手动创建。
使用Express生成器
# 安装Express生成器
npm install -g express-generator
# 创建项目
express myapp
# 进入项目目录并安装依赖
cd myapp
npm install
手动创建项目(推荐)
# 创建项目目录
mkdir myapp && cd myapp
# 初始化package.json
npm init -y
# 安装Express
npm install express --save
第一个Express应用
创建index.js文件,输入以下代码:
// 引用自[hello-world示例](https://gitcode.com/gh_mirrors/exp/express/blob/4cf7eed927d3ccd3f1d0c9a14d562ec0a1635e86/examples/hello-world/index.js?utm_source=gitcode_repo_files)
'use strict'
var express = require('express');
var app = module.exports = express()
app.get('/', function(req, res){
res.send('Hello World');
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
运行应用:
node index.js
访问http://localhost:3000,你将看到"Hello World"消息。恭喜,你已经成功创建了第一个Express应用!
核心概念详解
路由(Route)
路由是Express应用的核心,它定义了如何响应客户端对特定端点的请求。
基本路由定义
// 基本GET路由
app.get('/', function(req, res) {
res.send('GET request to homepage');
});
// 基本POST路由
app.post('/', function(req, res) {
res.send('POST request to homepage');
});
// 匹配所有HTTP方法的路由
app.all('/secret', function(req, res, next) {
console.log('Accessing the secret section...');
next(); // 调用next()将控制权传递给下一个中间件
});
路由路径与参数
Express支持多种路由路径定义方式:
// 路径匹配
app.get('/about', function(req, res) {
res.send('About page');
});
// 参数匹配
app.get('/users/:userId/books/:bookId', function(req, res) {
res.send(req.params);
});
// 正则表达式匹配
app.get(/.*fly$/, function(req, res) {
res.send('Butterfly or Dragonfly?');
});
路由分离与模块化
对于大型应用,建议将路由分离到单独的模块中,如路由分离示例所示:
// routes/users.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('User list');
});
router.get('/:id', function(req, res) {
res.send('User ID: ' + req.params.id);
});
module.exports = router;
// app.js
var usersRouter = require('./routes/users');
app.use('/users', usersRouter);
中间件(Middleware)
中间件是处理请求和响应的函数,可以访问请求对象(req)、响应对象(res)和应用的请求-响应循环中的下一个中间件函数。
中间件类型
Express中间件主要分为以下几类:
| 类型 | 说明 | 示例 |
|---|---|---|
| 应用级中间件 | 绑定到app对象,对所有请求生效 | app.use(express.json()) |
| 路由级中间件 | 绑定到router对象,只对特定路由生效 | router.use(authMiddleware) |
| 错误处理中间件 | 处理请求过程中发生的错误 | app.use(function(err, req, res, next) { ... }) |
| 内置中间件 | Express内置的中间件 | express.static(), express.json() |
| 第三方中间件 | 第三方提供的中间件 | morgan, cookie-parser |
常用内置中间件
Express 4.x版本内置了以下常用中间件:
// 解析JSON请求体
app.use(express.json());
// 解析URL编码的请求体
app.use(express.urlencoded({ extended: true }));
// 提供静态文件服务
app.use(express.static('public'));
自定义中间件
创建一个简单的日志中间件:
var logger = function(req, res, next) {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // 必须调用next()才能将控制权传递给下一个中间件
};
// 应用到所有请求
app.use(logger);
// 应用到特定路由
app.use('/users', logger);
请求对象(Request)与响应对象(Response)
Express封装了Node.js原生的HTTP请求和响应对象,提供了更便捷的API。
常用Request属性和方法
// 请求方法
req.method
// 请求URL
req.originalUrl
// 请求参数
req.params // 路由参数
req.query // 查询字符串参数
req.body // 请求体数据(需要body-parser中间件)
req.cookies // Cookie数据(需要cookie-parser中间件)
// 请求头
req.get('Content-Type')
// 其他方法
req.accepts() // 检查可接受的响应类型
req.is() // 检查请求体类型
req.range() // 解析Range请求头
常用Response属性和方法
// 响应状态码
res.status(code)
// 发送响应
res.send([body]) // 发送各种类型的响应
res.json([body]) // 发送JSON响应
res.sendFile(path) // 发送文件
res.render(view, [locals])// 渲染视图模板
// 设置响应头
res.set(field, [value])
res.header(field, [value])
// 重定向
res.redirect([status,] path)
// Cookie操作
res.cookie(name, value, [options])
res.clearCookie(name, [options])
// 其他方法
res.format() // 根据请求的Accept头发送不同格式的响应
res.attachment() // 设置Content-Disposition头
res.links(links) // 设置Link响应头
模板引擎与视图
配置模板引擎
Express支持多种模板引擎,如EJS、Handlebars、Pug等。以下是配置EJS模板引擎的示例:
// 引用自[MVC示例](https://gitcode.com/gh_mirrors/exp/express/blob/4cf7eed927d3ccd3f1d0c9a14d562ec0a1635e86/examples/mvc/index.js?utm_source=gitcode_repo_files)
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
常用的模板引擎及其配置:
| 模板引擎 | 安装命令 | 配置代码 |
|---|---|---|
| EJS | npm install ejs --save | app.set('view engine', 'ejs') |
| Pug | npm install pug --save | app.set('view engine', 'pug') |
| Handlebars | npm install hbs --save | app.set('view engine', 'hbs') |
创建和渲染视图
在views目录下创建EJS模板文件index.ejs:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= message %></h1>
<ul>
<% users.forEach(function(user) { %>
<li><%= user.name %></li>
<% }) %>
</ul>
</body>
</html>
在路由中渲染视图:
app.get('/', function(req, res) {
res.render('index', {
title: 'Express Demo',
message: 'Welcome to Express!',
users: [
{ name: 'Alice' },
{ name: 'Bob' },
{ name: 'Charlie' }
]
});
});
布局和局部视图
EJS本身不直接支持布局,但可以通过ejs-mate模块添加布局功能:
npm install ejs-mate --save
配置ejs-mate:
var ejsMate = require('ejs-mate');
app.engine('ejs', ejsMate);
app.set('view engine', 'ejs');
创建布局文件views/layouts/main.ejs:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<header>
<h1>My App</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>
<%- body %>
</main>
<footer>
© <%= new Date().getFullYear() %> My App
</footer>
</body>
</html>
在视图中使用布局:
<% layout('layouts/main') %>
<h2><%= message %></h2>
<p>This is the home page content.</p>
数据处理与数据库集成
使用body-parser处理请求体
虽然Express 4.16+已内置了JSON和URL编码解析功能,但了解如何处理请求数据仍然很重要:
// 解析JSON请求体
app.use(express.json());
// 解析URL编码的请求体
app.use(express.urlencoded({ extended: true }));
// 处理PUT请求示例
app.put('/users/:id', function(req, res) {
console.log(req.body); // 包含解析后的请求体数据
res.json({
status: 'success',
data: req.body
});
});
连接MongoDB数据库
使用Mongoose ODM连接MongoDB:
npm install mongoose --save
创建数据库连接:
var mongoose = require('mongoose');
// 连接MongoDB
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('MongoDB connected'))
.catch(err => console.log('MongoDB connection error:', err));
// 定义用户模型
var UserSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true },
age: Number,
createdAt: { type: Date, default: Date.now }
});
var User = mongoose.model('User', UserSchema);
// 使用模型
app.get('/users', async function(req, res) {
try {
var users = await User.find();
res.json(users);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
使用Sequelize连接关系型数据库
Sequelize是一个Node.js的ORM框架,支持PostgreSQL、MySQL、SQLite和MSSQL:
npm install sequelize mysql2 --save
创建Sequelize实例:
const { Sequelize, DataTypes } = require('sequelize');
// 创建Sequelize实例
const sequelize = new Sequelize('myapp', 'username', 'password', {
host: 'localhost',
dialect: 'mysql'
});
// 定义模型
const User = sequelize.define('User', {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
age: DataTypes.INTEGER
});
// 同步模型并使用
sequelize.sync()
.then(() => console.log('Models synced'))
.catch(err => console.log('Sync error:', err));
app.get('/users', async function(req, res) {
try {
const users = await User.findAll();
res.json(users);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
错误处理
错误处理中间件
Express使用特殊的错误处理中间件来处理请求过程中发生的错误,它有四个参数:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: req.app.get('env') === 'development' ? err : {}
});
});
自定义错误类
创建自定义错误类可以更好地组织错误处理逻辑:
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
// 使用自定义错误
app.get('/users/:id', async function(req, res, next) {
try {
const user = await User.findById(req.params.id);
if (!user) {
return next(new AppError('User not found', 404));
}
res.json(user);
} catch (err) {
next(err);
}
});
404错误处理
处理未匹配到路由的请求:
// 404处理中间件
app.use(function(req, res, next) {
res.status(404).render('404', {
url: req.originalUrl
});
});
实战:构建MVC应用
MVC架构概述
MVC(Model-View-Controller)是一种软件架构模式,将应用分为三个主要部分:
- 模型(Model):处理数据逻辑和数据库交互
- 视图(View):负责数据展示
- 控制器(Controller):处理用户请求,协调模型和视图
项目结构设计
参考MVC示例,一个典型的Express MVC项目结构如下:
myapp/
├── app.js # 应用入口
├── package.json
├── controllers/ # 控制器目录
│ ├── userController.js
│ └── postController.js
├── models/ # 模型目录
│ ├── userModel.js
│ └── postModel.js
├── views/ # 视图目录
│ ├── index.ejs
│ ├── users/
│ └── posts/
├── routes/ # 路由目录
│ ├── userRoutes.js
│ └── postRoutes.js
├── middleware/ # 中间件目录
│ ├── auth.js
│ └── logger.js
├── public/ # 静态文件目录
│ ├── css/
│ ├── js/
│ └── images/
└── config/ # 配置文件目录
├── database.js
└── app.js
实现用户认证功能
以下是一个简单的用户认证实现:
1. 创建用户模型(models/user.js)
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true,
minlength: 6
}
});
// 密码加密中间件
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);
};
module.exports = mongoose.model('User', userSchema);
2. 创建认证中间件(middleware/auth.js)
const jwt = require('jsonwebtoken');
const User = require('../models/user');
const AppError = require('../utils/appError');
module.exports = async function(req, res, next) {
try {
// 获取token
let token;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
token = req.headers.authorization.split(' ')[1];
}
if (!token) {
return next(new AppError('Not authorized to access this route', 401));
}
// 验证token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// 查找用户
const user = await User.findById(decoded.id).select('-password');
if (!user) {
return next(new AppError('User not found', 404));
}
// 将用户信息添加到请求对象
req.user = user;
next();
} catch (error) {
next(new AppError('Not authorized to access this route', 401));
}
};
3. 创建用户控制器(controllers/userController.js)
const User = require('../models/user');
const jwt = require('jsonwebtoken');
const AppError = require('../utils/appError');
// 生成JWT令牌
const generateToken = (id) => {
return jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: '30d'
});
};
// 用户注册
exports.register = async (req, res, next) => {
try {
const { username, email, password } = req.body;
// 创建用户
const user = await User.create({
username,
email,
password
});
// 生成令牌
const token = generateToken(user._id);
res.status(201).json({
status: 'success',
token,
data: {
user: {
id: user._id,
username: user.username,
email: user.email
}
}
});
} catch (error) {
next(error);
}
};
// 用户登录
exports.login = async (req, res, next) => {
try {
const { email, password } = req.body;
// 检查用户是否存在
const user = await User.findOne({ email });
if (!user || !(await user.comparePassword(password))) {
return next(new AppError('Invalid email or password', 401));
}
// 生成令牌
const token = generateToken(user._id);
res.status(200).json({
status: 'success',
token,
data: {
user: {
id: user._id,
username: user.username,
email: user.email
}
}
});
} catch (error) {
next(error);
}
};
// 获取当前用户信息
exports.getMe = async (req, res, next) => {
try {
res.status(200).json({
status: 'success',
data: {
user: req.user
}
});
} catch (error) {
next(error);
}
};
4. 创建用户路由(routes/userRoutes.js)
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const authMiddleware = require('../middleware/auth');
// 公开路由
router.post('/register', userController.register);
router.post('/login', userController.login);
// 保护路由
router.get('/me', authMiddleware, userController.getMe);
module.exports = router;
5. 在app.js中注册路由
const userRoutes = require('./routes/userRoutes');
app.use('/api/users', userRoutes);
性能优化与部署
性能优化技巧
- 使用压缩中间件
const compression = require('compression');
app.use(compression());
- 缓存静态资源
app.use(express.static('public', {
maxAge: '1d',
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
res.setHeader('Cache-Control', 'public, max-age=0');
}
}
}));
- 使用集群模式
利用Node.js的cluster模块充分利用多核CPU:
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// 衍生工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork(); // 重启工作进程
});
} else {
// 工作进程运行Express应用
app.listen(3000, () => {
console.log(`Worker ${process.pid} started`);
});
}
- 数据库查询优化
- 使用索引
- 限制返回字段
- 使用分页加载大量数据
- 实现数据缓存
部署Express应用
使用PM2进行进程管理
PM2是一个Node.js应用的进程管理器,可以实现应用的后台运行、自动重启和负载均衡:
# 安装PM2
npm install -g pm2
# 启动应用
pm2 start app.js --name "myapp"
# 查看应用状态
pm2 status
# 查看日志
pm2 logs
# 设置开机自启
pm2 startup
pm2 save
使用Nginx作为反向代理
配置Nginx作为反向代理,处理静态资源并将API请求转发给Express应用:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /static {
alias /path/to/your/app/public;
expires 1d;
}
}
总结与进阶学习
本文总结
通过本文,你已经学习了Express.js的核心概念和使用方法,包括:
- Express.js的架构和请求处理流程
- 环境搭建和项目初始化
- 路由设计和中间件使用
- 请求和响应对象的操作
- 模板引擎和视图管理
- 数据库集成和数据处理
- 错误处理机制
- MVC架构和项目实战
- 性能优化和部署方法
进阶学习资源
-
官方文档:Express官方文档提供了最权威的参考资料
-
高级中间件:
helmet:安全相关的HTTP头设置cors:处理跨域资源共享rate-limit:请求频率限制morgan:HTTP请求日志
-
API设计:
- RESTful API设计原则
- GraphQL与Express集成
-
测试:
- Mocha和Chai进行单元测试
- Supertest测试HTTP接口
- Jest进行组件测试
-
微服务:
- Express与微服务架构
- API网关设计
Express.js作为一个灵活高效的Web框架,为Node.js开发提供了强大的支持。通过不断实践和探索,你可以构建出更加复杂和高性能的Web应用。祝你在Express.js的学习之路上取得更多成就!
附录:常用Express中间件和工具
| 名称 | 功能 | 安装命令 |
|---|---|---|
| morgan | HTTP请求日志 | npm install morgan |
| helmet | 安全HTTP头 | npm install helmet |
| cors | 跨域资源共享 | npm install cors |
| compression | 响应压缩 | npm install compression |
| cookie-parser | Cookie解析 | npm install cookie-parser |
| express-session | Session管理 | npm install express-session |
| connect-flash | 闪存消息 | npm install connect-flash |
| multer | 文件上传 | npm install multer |
| express-validator | 请求数据验证 | npm install express-validator |
| winston | 日志记录 | npm install winston |
【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



