最完整Express.js入门指南:从零构建Node.js应用

最完整Express.js入门指南:从零构建Node.js应用

【免费下载链接】express 【免费下载链接】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的核心架构由以下几个关键部分组成:

mermaid

核心组件说明:

  • Application(应用):Express应用的入口点,通过express()创建,负责全局配置和中间件管理
  • Router(路由器):负责请求的路由分发,可创建多个独立的路由器
  • Route(路由):定义特定HTTP方法和路径的处理逻辑
  • Layer(层):封装中间件和路由处理器,构成处理管道

Express.js请求处理流程

当一个请求到达Express应用时,会经过以下处理流程:

mermaid

关键代码实现可参考应用类实现路由器实现

环境搭建与项目初始化

安装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'));

常用的模板引擎及其配置:

模板引擎安装命令配置代码
EJSnpm install ejs --saveapp.set('view engine', 'ejs')
Pugnpm install pug --saveapp.set('view engine', 'pug')
Handlebarsnpm install hbs --saveapp.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>
        &copy; <%= 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)是一种软件架构模式,将应用分为三个主要部分:

mermaid

  • 模型(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);

性能优化与部署

性能优化技巧

  1. 使用压缩中间件
const compression = require('compression');
app.use(compression());
  1. 缓存静态资源
app.use(express.static('public', {
    maxAge: '1d',
    setHeaders: (res, path) => {
        if (path.endsWith('.html')) {
            res.setHeader('Cache-Control', 'public, max-age=0');
        }
    }
}));
  1. 使用集群模式

利用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`);
    });
}
  1. 数据库查询优化
  • 使用索引
  • 限制返回字段
  • 使用分页加载大量数据
  • 实现数据缓存

部署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架构和项目实战
  • 性能优化和部署方法

进阶学习资源

  1. 官方文档Express官方文档提供了最权威的参考资料

  2. 高级中间件

    • helmet:安全相关的HTTP头设置
    • cors:处理跨域资源共享
    • rate-limit:请求频率限制
    • morgan:HTTP请求日志
  3. API设计

    • RESTful API设计原则
    • GraphQL与Express集成
  4. 测试

    • Mocha和Chai进行单元测试
    • Supertest测试HTTP接口
    • Jest进行组件测试
  5. 微服务

    • Express与微服务架构
    • API网关设计

Express.js作为一个灵活高效的Web框架,为Node.js开发提供了强大的支持。通过不断实践和探索,你可以构建出更加复杂和高性能的Web应用。祝你在Express.js的学习之路上取得更多成就!

附录:常用Express中间件和工具

名称功能安装命令
morganHTTP请求日志npm install morgan
helmet安全HTTP头npm install helmet
cors跨域资源共享npm install cors
compression响应压缩npm install compression
cookie-parserCookie解析npm install cookie-parser
express-sessionSession管理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 【免费下载链接】express 项目地址: https://gitcode.com/gh_mirrors/exp/express

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值