Node.js Express 框架入门

核心知识点

Express 框架简介

Express 是一个基于 Node.js 平台的快速、开放、极简的 Web 开发框架。它提供了一系列强大的特性,用于构建 Web 和移动应用的 API。

Express 的主要特点:

  • 极简的核心,灵活的中间件机制
  • 强大的路由系统
  • 内置的模板引擎支持
  • 丰富的 HTTP 工具方法
  • 良好的性能

安装 Express

使用 npm 安装 Express:

# 创建项目目录
mkdir my-express-app
cd my-express-app

# 初始化项目
npm init -y

# 安装 Express
npm install express

创建 Express 应用

创建一个基本的 Express 应用:

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

// 定义路由
app.get('/', (req, res) => {
  res.send('Hello, Express!');
});

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

中间件

中间件是 Express 的核心概念,它是一个函数,能够访问请求对象 (req)、响应对象 (res) 和应用的请求-响应循环中的下一个中间件函数。

// 应用级中间件
app.use((req, res, next) => {
  console.log('时间:', Date.now());
  next(); // 调用下一个中间件
});

// 路由级中间件
app.get('/user/:id', (req, res, next) => {
  if (req.params.id === '0') next('route'); // 跳过当前路由的剩余中间件
  else next(); // 调用下一个中间件
}, (req, res) => {
  res.send('常规');
});

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

路由

Express 提供了强大的路由系统,用于处理不同的 HTTP 请求:

// 基本路由
app.get('/', (req, res) => {
  res.send('GET 请求');
});

app.post('/', (req, res) => {
  res.send('POST 请求');
});

app.put('/user', (req, res) => {
  res.send('PUT 请求');
});

app.delete('/user', (req, res) => {
  res.send('DELETE 请求');
});

响应方法

Express 提供了多种响应方法,用于结束请求-响应循环:

  • res.download():提示下载文件
  • res.end():结束响应进程
  • res.json():发送 JSON 响应
  • res.jsonp():发送支持 JSONP 的 JSON 响应
  • res.redirect():重定向请求
  • res.render():渲染视图模板
  • res.send():发送各种类型的响应
  • res.sendFile():发送文件
  • res.sendStatus():发送状态码

实用案例

案例一:基本 Express 应用

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

// 应用级中间件
app.use((req, res, next) => {
  console.log(`${new Date()} - ${req.method} ${req.url}`);
  next();
});

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

app.get('/about', (req, res) => {
  res.send('关于我们');
});

app.get('/contact', (req, res) => {
  res.send('联系我们');
});

// 404 处理
app.use((req, res) => {
  res.status(404).send('404 Not Found');
});

// 启动服务器
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

案例二:路由参数

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

// 带参数的路由
app.get('/user/:id', (req, res) => {
  const userId = req.params.id;
  res.send(`用户 ID: ${userId}`);
});

// 多个参数
app.get('/user/:id/books/:bookId', (req, res) => {
  const { id, bookId } = req.params;
  res.send(`用户 ID: ${id}, 书籍 ID: ${bookId}`);
});

// 可选参数
app.get('/products/:category/:id?', (req, res) => {
  const { category, id } = req.params;
  if (id) {
    res.send(`分类: ${category}, 产品 ID: ${id}`);
  } else {
    res.send(`分类: ${category}, 显示所有产品`);
  }
});

// 启动服务器
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

案例三:查询参数

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

// 查询参数
app.get('/search', (req, res) => {
  const query = req.query;
  res.json({
    message: '搜索结果',
    query: query
  });
});

// 带默认值的查询参数
app.get('/greet', (req, res) => {
  const name = req.query.name || 'World';
  const age = req.query.age || '未知';
  res.send(`Hello, ${name}! 年龄: ${age}`);
});

// 计算两个数的和
app.get('/add', (req, res) => {
  const a = parseInt(req.query.a) || 0;
  const b = parseInt(req.query.b) || 0;
  const sum = a + b;
  res.send(`${a} + ${b} = ${sum}`);
});

// 启动服务器
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

案例四:静态文件服务

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

// 提供静态文件服务
app.use(express.static(path.join(__dirname, 'public')));

// 也可以为静态文件指定虚拟路径
app.use('/static', express.static(path.join(__dirname, 'public')));

// 路由
app.get('/', (req, res) => {
  res.send('首页');
});

// 启动服务器
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

案例五:中间件链

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

// 中间件 1:日志
app.use((req, res, next) => {
  console.log('中间件 1: 记录请求');
  next();
});

// 中间件 2:认证
app.use((req, res, next) => {
  console.log('中间件 2: 认证检查');
  // 模拟认证成功
  req.user = { id: 1, name: '用户' };
  next();
});

// 路由中间件
app.get('/protected', (req, res, next) => {
  console.log('路由中间件: 处理受保护的路由');
  next();
}, (req, res) => {
  res.send(`欢迎, ${req.user.name}! 这是受保护的页面`);
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error('错误:', err);
  res.status(500).send('服务器错误');
});

// 启动服务器
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

学习目标

  1. 理解 Express 框架:掌握 Express 的基本概念和核心特性
  2. 安装和配置:学会安装 Express 并创建基本应用
  3. 使用路由:能够定义和处理不同类型的 HTTP 请求
  4. 中间件使用:理解并使用中间件处理请求
  5. 静态文件服务:学会提供静态文件服务
  6. 参数处理:能够处理路由参数和查询参数

代码优化建议

1. 模块化路由

不好的做法

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

// 所有路由都在一个文件中
app.get('/', (req, res) => {...});
app.get('/users', (req, res) => {...});
app.get('/users/:id', (req, res) => {...});
app.get('/products', (req, res) => {...});
app.get('/products/:id', (req, res) => {...});

app.listen(3000);

好的做法

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

router.get('/', (req, res) => {...});
router.get('/:id', (req, res) => {...});

module.exports = router;

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

router.get('/', (req, res) => {...});
router.get('/:id', (req, res) => {...});

module.exports = router;

// app.js
const express = require('express');
const app = express();
const userRoutes = require('./routes/users');
const productRoutes = require('./routes/products');

app.use('/users', userRoutes);
app.use('/products', productRoutes);

app.listen(3000);

2. 使用环境变量

不好的做法

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

// 硬编码端口
const port = 3000;
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

好的做法

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

// 使用环境变量
const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`服务器运行在 http://localhost:${port}`);
});

3. 错误处理

不好的做法

app.get('/api/data', (req, res) => {
  // 没有错误处理
  const data = someFunctionThatMightThrow();
  res.json(data);
});

好的做法

app.get('/api/data', (req, res, next) => {
  try {
    const data = someFunctionThatMightThrow();
    res.json(data);
  } catch (error) {
    next(error); // 传递给错误处理中间件
  }
});

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error('错误:', err);
  res.status(500).json({ error: '服务器内部错误' });
});

常见问题与解决方案

问题1:Express 应用启动失败

原因

  • 端口被占用
  • 依赖项未安装

解决方案

  • 更改端口号
  • 运行 npm install 安装依赖

问题2:静态文件无法访问

原因

  • 文件路径错误
  • 静态文件中间件配置错误

解决方案

  • 检查文件路径是否正确
  • 确保静态文件中间件在路由之前配置

问题3:路由不匹配

原因

  • 路由顺序错误
  • 路径定义错误

解决方案

  • 将具体路由放在通配符路由之前
  • 检查路径定义是否正确

问题4:中间件不执行

原因

  • 中间件顺序错误
  • 没有调用 next()

解决方案

  • 调整中间件顺序
  • 确保在中间件中调用 next()

总结

通过本教程的学习,你应该能够:

  1. 理解 Express 框架的基本概念和核心特性
  2. 安装 Express 并创建基本的 Web 应用
  3. 定义和处理不同类型的 HTTP 请求
  4. 使用中间件处理请求和响应
  5. 提供静态文件服务
  6. 处理路由参数和查询参数
  7. 构建模块化、可维护的 Express 应用

Express 是 Node.js 生态系统中最流行的 Web 框架之一,它的简洁性和灵活性使其成为构建各种 Web 应用和 API 的理想选择。在后续章节中,我们将深入学习 Express 的更多高级特性,如模板引擎、数据库集成、认证授权等。

« 上一篇 Node.js HTTP 服务器进阶 下一篇 » Express 路由与请求处理