Skip to content

Express 框架实战

Express 是一个基于 Node.js 平台的 Web 应用框架,它提供了简洁而灵活的 API,用于构建 Web 应用和 API。本文将介绍 Express 框架的核心概念和使用方法。

1. 安装 Express

bash
# 初始化项目
npm init -y

# 安装 Express
npm install express

2. 基本使用

创建服务器

javascript
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

路由

javascript
// 基本路由
app.get('/', (req, res) => {
  res.send('Home page');
});

app.post('/submit', (req, res) => {
  res.send('Form submitted');
});

app.put('/update', (req, res) => {
  res.send('Resource updated');
});

app.delete('/delete', (req, res) => {
  res.send('Resource deleted');
});

// 路由参数
app.get('/users/:id', (req, res) => {
  const id = req.params.id;
  res.send(`User ID: ${id}`);
});

// 查询参数
app.get('/search', (req, res) => {
  const query = req.query;
  res.send(`Search query: ${JSON.stringify(query)}`);
});

中间件

javascript
// 内置中间件
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码的请求体
app.use(express.static('public')); // 提供静态文件

// 自定义中间件
app.use((req, res, next) => {
  console.log('Request received');
  next(); // 调用 next() 继续处理请求
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

3. 路由系统

基本路由

javascript
app.get('/', (req, res) => {
  res.send('Home page');
});

app.post('/submit', (req, res) => {
  res.send('Form submitted');
});

路由参数

javascript
app.get('/users/:id', (req, res) => {
  const id = req.params.id;
  res.send(`User ID: ${id}`);
});

app.get('/users/:id/posts/:postId', (req, res) => {
  const { id, postId } = req.params;
  res.send(`User ID: ${id}, Post ID: ${postId}`);
});

路由处理函数

javascript
// 单个处理函数
app.get('/users', (req, res) => {
  res.send('Users list');
});

// 多个处理函数
app.get('/users', (req, res, next) => {
  console.log('First handler');
  next();
}, (req, res) => {
  res.send('Users list');
});

// 处理函数数组
const middleware1 = (req, res, next) => {
  console.log('Middleware 1');
  next();
};

const middleware2 = (req, res, next) => {
  console.log('Middleware 2');
  next();
};

app.get('/users', [middleware1, middleware2], (req, res) => {
  res.send('Users list');
});

路由模块

javascript
// routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.send('Users list');
});

router.get('/:id', (req, res) => {
  res.send(`User ID: ${req.params.id}`);
});

module.exports = router;

// app.js
const express = require('express');
const app = express();
const usersRouter = require('./routes/users');

app.use('/users', usersRouter);

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

4. 中间件

应用级中间件

javascript
app.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

app.use('/users', (req, res, next) => {
  console.log('Request to /users');
  next();
});

路由级中间件

javascript
const express = require('express');
const router = express.Router();

router.use((req, res, next) => {
  console.log('Time:', Date.now());
  next();
});

router.get('/', (req, res) => {
  res.send('Users list');
});

app.use('/users', router);

错误处理中间件

javascript
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

内置中间件

javascript
app.use(express.json()); // 解析 JSON 请求体
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码的请求体
app.use(express.static('public')); // 提供静态文件

第三方中间件

bash
# 安装中间件
npm install morgan cors helmet
javascript
const express = require('express');
const morgan = require('morgan');
const cors = require('cors');
const helmet = require('helmet');

const app = express();

app.use(morgan('dev')); // 日志中间件
app.use(cors()); // 跨域中间件
app.use(helmet()); // 安全中间件

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

5. 请求与响应

请求对象 (req)

javascript
app.get('/users/:id', (req, res) => {
  // 路由参数
  const id = req.params.id;
  
  // 查询参数
  const query = req.query;
  
  // 请求头
  const headers = req.headers;
  
  // 请求体
  const body = req.body;
  
  // 请求方法
  const method = req.method;
  
  // 请求路径
  const path = req.path;
  
  // 完整 URL
  const url = req.originalUrl;
  
  res.send(`User ID: ${id}`);
});

响应对象 (res)

javascript
app.get('/users', (req, res) => {
  // 发送文本
  res.send('Users list');
  
  // 发送 JSON
  res.json({ users: [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] });
  
  // 发送文件
  res.sendFile(__dirname + '/index.html');
  
  // 重定向
  res.redirect('/');
  
  // 设置状态码
  res.status(200).send('OK');
  
  // 设置头部
  res.set('Content-Type', 'application/json');
  
  // 发送状态码和消息
  res.status(404).send('Not found');
});

6. 模板引擎

安装模板引擎

bash
npm install ejs

配置模板引擎

javascript
const express = require('express');
const app = express();

// 设置模板引擎
app.set('view engine', 'ejs');

// 设置模板目录
app.set('views', './views');

app.get('/', (req, res) => {
  res.render('index', { title: 'Home', message: 'Hello World!' });
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

创建模板文件

ejs
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head>
  <title><%= title %></title>
</head>
<body>
  <h1><%= message %></h1>
  <ul>
    <% for (let user of users) { %>
      <li><%= user.name %></li>
    <% } %>
  </ul>
</body>
</html>

7. 静态文件

javascript
const express = require('express');
const app = express();

// 提供静态文件
app.use(express.static('public'));

// 为静态文件设置虚拟路径
app.use('/static', express.static('public'));

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

8. 错误处理

404 错误

javascript
app.use((req, res, next) => {
  res.status(404).send('Not found');
});

500 错误

javascript
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

自定义错误处理

javascript
class CustomError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
  }
}

app.get('/error', (req, res, next) => {
  next(new CustomError('Custom error', 400));
});

app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  res.status(statusCode).send(err.message);
});

9. 数据库集成

MongoDB

bash
npm install mongoose
javascript
const express = require('express');
const mongoose = require('mongoose');

const app = express();

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

// 定义模型
const User = mongoose.model('User', {
  name: String,
  email: String
});

app.get('/users', async (req, res) => {
  try {
    const users = await User.find();
    res.json(users);
  } catch (err) {
    res.status(500).send(err.message);
  }
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

MySQL

bash
npm install mysql2
javascript
const express = require('express');
const mysql = require('mysql2');

const app = express();

// 创建连接
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'myapp'
});

// 连接数据库
connection.connect();

app.get('/users', (req, res) => {
  connection.query('SELECT * FROM users', (err, results) => {
    if (err) {
      res.status(500).send(err.message);
      return;
    }
    res.json(results);
  });
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

10. 认证与授权

JWT 认证

bash
npm install jsonwebtoken
javascript
const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();
app.use(express.json());

// 生成 token
function generateToken(user) {
  return jwt.sign({ id: user.id, name: user.name }, 'secret_key', { expiresIn: '1h' });
}

// 验证 token
function verifyToken(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) {
    return res.status(401).send('Access denied');
  }
  try {
    const decoded = jwt.verify(token, 'secret_key');
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).send('Invalid token');
  }
}

// 登录路由
app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // 验证用户
  const user = { id: 1, name: 'John' };
  const token = generateToken(user);
  res.json({ token });
});

// 受保护的路由
app.get('/protected', verifyToken, (req, res) => {
  res.send(`Welcome, ${req.user.name}!`);
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

11. 测试

单元测试

bash
npm install --save-dev mocha chai supertest
javascript
// test.js
const request = require('supertest');
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello World!');
});

describe('GET /', () => {
  it('should return 200 OK', (done) => {
    request(app)
      .get('/')
      .expect(200)
      .expect('Hello World!', done);
  });
});
bash
# 运行测试
npx mocha test.js

集成测试

javascript
// test-integration.js
const request = require('supertest');
const app = require('./app');

describe('GET /users', () => {
  it('should return users list', (done) => {
    request(app)
      .get('/users')
      .expect(200)
      .expect('Content-Type', /json/)
      .end((err, res) => {
        if (err) return done(err);
        done();
      });
  });
});

12. 部署

本地部署

bash
# 安装依赖
npm install

# 运行应用
npm start

云部署

Heroku

  1. 安装 Heroku CLI
  2. 登录 Heroku:heroku login
  3. 创建 Heroku 应用:heroku create
  4. 部署代码:git push heroku master
  5. 打开应用:heroku open

AWS

  1. 创建 EC2 实例
  2. 安装 Node.js
  3. 上传代码
  4. 安装依赖
  5. 运行应用

Docker

dockerfile
FROM node:14

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

13. 最佳实践

  1. 模块化:将代码拆分为多个模块
  2. 中间件:合理使用中间件
  3. 路由:使用路由模块组织路由
  4. 错误处理:统一处理错误
  5. 数据库:使用 ORM 或 ODM
  6. 认证:使用 JWT 或其他认证方式
  7. 测试:编写单元测试和集成测试
  8. 日志:使用日志中间件
  9. 安全:使用安全中间件
  10. 性能:优化性能

14. 性能优化

  1. 使用 gzip 压缩npm install compression
  2. 使用缓存npm install express-cache-controller
  3. 优化数据库查询:使用索引
  4. 使用连接池:减少数据库连接开销
  5. 使用负载均衡:分发请求
  6. 使用 CDN:加速静态资源
  7. 使用集群:利用多核 CPU

15. 总结

Express 是一个轻量级的 Web 应用框架,它提供了简洁而灵活的 API,用于构建 Web 应用和 API。通过学习 Express,我们可以快速构建高性能的后端应用程序。

Express 的核心特性包括:

  • 简洁的 API
  • 强大的路由系统
  • 灵活的中间件
  • 支持模板引擎
  • 易于集成数据库

Express 已经成为 Node.js 生态系统中最流行的 Web 框架之一,许多大型公司都在使用 Express 构建他们的应用程序。掌握 Express 是现代后端开发者的必备技能。