当前位置: 首页 > ds >正文

1.9 Express

Express 是一个基于 Node.js 平台的轻量级、灵活的 Web 应用框架,它为构建 Web 应用和 API 提供了一系列强大的功能。

核心特性

  1. 中间件支持:Express 使用中间件(middleware)函数来处理 HTTP 请求和响应。中间件可以访问请求对象(req)、响应对象(res),以及应用程序的请求-响应循环中的下一个中间件函数。通过中间件,你可以执行各种任务,如日志记录、解析请求体、路由处理等。

  2. 路由:Express 提供了简洁而灵活的路由机制,允许你根据不同的 HTTP 方法(GET, POST 等)和 URL 路径定义处理逻辑。你可以创建复杂的路由结构,并且支持动态路由参数。

  3. 视图系统:Express 支持多种模板引擎,如 EJS、Pug、Handlebars 等,使得你可以轻松地生成 HTML 页面。

  4. 错误处理:内置错误处理机制,可以通过特定的中间件来捕获并处理应用中的错误。

  5. 与数据库集成:虽然 Express 本身不绑定任何数据库,但其灵活性意味着它可以轻松地与 MongoDB、MySQL、PostgreSQL 等数据库集成。

快速入门

安装 Express:

npm install express --save

创建一个简单的服务器:

const express = require('express');
const app = express();app.get('/', (req, res) => {res.send('Hello World!');
});app.listen(3000, () => {console.log('Server is running on port 3000.');
});

Express兼容原生http响应

Express 中,响应对象(res)是对 Node.js 原生 http.ServerResponse 对象的扩展,因此它兼容原生 HTTP 的响应方法。这意味着你可以使用原生的方法,也可以使用由 Express 提供的更高级的 API 来发送响应。

//原生 Node.js:
//使用 res.statusCode、res.setHeader、res.writeconst express = require('express');
const http = require('http');const app = express();// Express 中间件处理
app.use((req, res, next) => {// 原生 HTTP 响应方法示例res.statusCode = 200;res.setHeader('Content-Type', 'text/plain');res.write('Hello from Express with native HTTP!');// 继续 Express 流程next();
});// Express 路由处理
app.get('/', (req, res) => {// 可以继续使用 Express APIres.end(' (with Express finish)');
});app.listen(3000, () => {console.log('Server running on port 3000');
});

原生 Node.js: 需要手动设置状态码为 3xx 并设置 Location 头。

response.writeHead(302, {Location: 'http://example.com'});
response.end();

Express: 使用便捷的 .redirect() 方法。

res.redirect('http://example.com');

Express 提供了便捷的方法如 .download() 和直接使用流(Stream)来响应文件下载请求。

这是 Express 特有的方法,用于触发文件下载,并自动设置适当的响应头(如 Content-Disposition: attachment)。

const express = require('express');
const app = express();
const path = require('path');app.get('/download', (req, res) => {const filePath = path.join(__dirname, 'public', 'example.txt');res.download(filePath); // 自动触发下载
});

参数说明:

  • res.download(filePath, [filename], [options], [callback])
    • filePath: 文件在服务器上的路径。
    • [filename]: 客户端看到的文件名(可选,默认为原始文件名)。
    • [options]: 可选配置对象,例如 { headers: { ... } }
    • [callback]: 下载完成后的回调函数。

原生 http 的方法时,你需要手动控制所有流程,包括读取文件、设置响应头、发送数据等

// const http = require('http');
const fs = require('fs');
const path = require('path');
const express = require('express');const app = express();// const server = http.createServer((req, res) => {
//   if (req.url === '/download') {
//     const filePath = path.join(__dirname,  'example.txt');//     res.writeHead(200, {
//       'Content-Type': 'application/octet-stream',
//       'Content-Disposition': 'attachment; filename="example.txt"'
//     });//     const readStream = fs.createReadStream(filePath);
//     readStream.pipe(res);
//   } else {
//     res.writeHead(404);
//     res.end('Not Found');
//   }
// });// server.listen(3000, () => {
//   console.log('Server running on port 3000');
// });app.get('/download', (req, res) => {const filePath = path.join(__dirname,  'example.txt');res.writeHead(200, {'Content-Type': 'application/octet-stream','Content-Disposition': 'attachment; filename="example.txt"'});const readStream = fs.createReadStream(filePath);readStream.pipe(res);
});app.listen(3000, () => {console.log('Server running on port 3000');});

express 特有的响应客户端方法

res.send()

自动根据传入数据类型设置合适的响应头,并发送响应体。

  • 如果是字符串:默认设置 Content-Type: text/html
  • 如果是对象或数组:自动调用 JSON.stringify(),并设置 Content-Type: application/json
  • 支持 Buffer 数据(如二进制)
res.send('Hello World'); // 发送 HTML 或纯文本
res.send({ name: 'Tom' }); // 自动转为 JSON 并设置 Content-Type: application/json
res.send(Buffer.from('ABC')); // 发送二进制数据
  • 智能处理不同类型的数据。
  • 不会触发浏览器下载行为。
  • 适合返回 API 响应、HTML 页面等。

res.json()

专门用于发送 JSON 格式的数据,自动调用 JSON.stringify() 并设置 Content-Type: application/json

res.json({ success: true, data: { id: 1 } });
// 输出:
// {"success":true,"data":{"id":1}}
  • 保证响应内容为标准 JSON 格式。

  • 设置正确的 Content-Type
  • 推荐用于构建 RESTful API。

⚠️ 注意:如果传入的是一个循环引用的对象,json() 会抛出错误。


res.sendFile()

用于发送一个文件给客户端(例如 HTML 文件、图片等),常用于静态资源服务。

const path = require('path');app.get('/', (req, res) => {res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
  • 必须传入文件的绝对路径(推荐使用 path.join() 构造)。

  • 自动设置适当的 MIME 类型(如 text/htmlimage/png 等)。
  • 不会强制浏览器下载,而是尝试在浏览器中直接显示(如 PDF、图片等)。
 res.status(code)
  • 用途:设置 HTTP 状态码。通常与其他响应方法链式使用。
  • res.status(404).send('Not Found');
 res.set(field [, value]) 或 res.header(field [, value])
  • 用途:设置 HTTP 响应头。
  • res.set('Content-Type', 'text/plain');
    // 或者
    res.set({'Content-Type': 'text/plain','ETag': '12345'
    });
 res.type(type) 或 res.contentType(type)
  • 用途:设置 Content-Type 响应头。type 参数可以是 MIME 类型或文件扩展名。
  • res.type('.html'); // Content-Type 设置为 text/html
    res.type('json'); // Content-Type 设置为 application/json

路由(Routing)

处理不同路径和 HTTP 方法的请求。

基本路由
// GET 请求
app.get('/users', (req, res) => { /* ... */ });// POST 请求
app.post('/users', (req, res) => { /* ... */ });// 动态路由参数
app.get('/users/:id', (req, res) => {const userId = req.params.id;res.send(`User ${userId}`);
});
路由分组

使用 express.Router 创建模块化路由:

// routes/users.js
const router = require('express').Router();router.get('/', (req, res) => { /* 获取所有用户 */ });
router.post('/', (req, res) => { /* 创建用户 */ });module.exports = router;// main.js
const userRoutes = require('./routes/users');
app.use('/api/users', userRoutes);

 中间件(Middleware)

Express 中,中间件是处理 HTTP 请求的核心机制,它允许你在请求到达路由处理函数之前或之后执行代码。中间件函数可以:

  1. 修改请求和响应对象(如添加属性、设置头部)
  2. 结束请求 - 响应循环(如返回错误或结果)
  3. 调用下一个中间件函数(通过 next()

内置中间件

// 解析 JSON 请求体
app.use(express.json());// 静态文件服务
app.use(express.static('public'));//有时你可能希望为静态文件添加一个路径前缀,可以通过将挂载点作为第一个参数传递给 express.static 实现:
app.use('/static', express.static('public'));
// 现在,你需要通过 /static/example.html 来访问 public 目录下的 example.html 文件//默认情况下,如果 express.static 找不到请求的文件,它不会发送下一个中间件。如果你想改变这种行为,可以让它继续执行后续的中间件:app.use(express.static('public', { fallthrough: true }));app.use((req, res, next) => {res.status(404).send('Sorry, we cannot find that!');
});
// 这将确保当静态文件未找到时,仍然有机会返回自定义的 404 页面或其他内容。

自定义中间件

中间件函数接收三个参数:(req, res, next)

  • req:HTTP 请求对象
  • res:HTTP 响应对象
  • next:指向下一个中间件的函数,必须调用它才能继续执行后续中间件
// 日志中间件
app.use((req, res, next) => {console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);next(); // 传递控制权给下一个中间件
});// 错误处理中间件(必须有 4 个参数)
app.use((err, req, res, next) => {console.error(err);res.status(500).send('Internal Server Error');
});

中间件的类型

1. 应用级中间件

绑定到 app 实例,处理所有路由请求:

// 记录所有请求的时间戳
app.use((req, res, next) => {req.requestTime = Date.now();next();
});
2. 路由级中间件

绑定到特定路由,只处理匹配的请求:

// 仅处理 /users 路径的请求
app.use('/users', (req, res, next) => {console.log('Processing user-related request');next();
});

3. 错误处理中间件

接收四个参数 (err, req, res, next),用于捕获和处理错误:

app.use((err, req, res, next) => {console.error(err.stack);res.status(500).send('Internal Server Error');
});

错误处理

错误处理中间件与普通中间件类似,但需要四个参数,其签名如下:(err, req, res, next)。即使你不使用 next 参数,也必须指定它,以便 Express 能够识别这是一个错误处理中间件。

统一处理应用中的异常:


app.get('/users',(req, res) => {try {const data = getData();req.data = data;next();} catch (err) {next(err); // 将错误传递给错误处理中间件}
});// 全局错误处理
app.use((err, req, res, next) => {const statusCode = err.statusCode || 500;res.status(statusCode).json({error: {message: err.message,status: statusCode}});
});

关键点解释

  1. 触发错误:在任何地方调用 next() 并传入一个错误对象,就可以将控制权交给第一个匹配的错误处理中间件。
  2. 错误处理中间件:使用 app.use() 来定义,它会捕捉所有通过 next(err) 传递过来的错误。
  3. 环境变量判断:在这个例子中,根据应用程序环境(development 或 production),决定是否向客户端暴露详细的错误信息。这有助于保护生产环境下的敏感信息泄露。
http://www.xdnf.cn/news/13687.html

相关文章:

  • Flutter 常用组件详解:Text、Button、Image、ListView 和 GridView
  • c++中main函数执行完后还执行其它语句吗?
  • FreeRTOS互斥量
  • 面向异构系统的多面体编译优化关键技术研究——李颖颖博士
  • Linux 任务调度策略
  • 一数一源一标准的补充
  • 论文阅读:强化预训练
  • 强化学习入门:交叉熵方法实现CartPole智能体
  • 一个超强的推理增强大模型,开源了,本地部署
  • 跨网数据摆渡系统:破解数据流通难题的“标准答案”
  • 别人如何访问我的内网呢? 设置让外网访问内网本地服务器和指定端口应用的几种方式
  • 曼昆《经济学原理》第九版 第十八章生产要素市场
  • Vue Electron 使用来给若依系统打包成exe程序,出现登录成功但是不跳转页面(已解决)
  • Vue 中 data 选项:对象 vs 函数
  • Rust 学习笔记:通过异步实现并发
  • 【题解-洛谷】P2935 [USACO09JAN] Best Spot S
  • 算法训练第十五天
  • docker推荐应用汇总及部署实战
  • ComfyUI-安装
  • 不装 ROS 也能用 PyKDL!使用kdl_parser解析URDF并进行IK
  • Linux-进程间的通信
  • 大数据服务器的特点都指什么?
  • Python----OpenCV(图像处理——边界填充、图像融合、图像阈值、深拷贝与浅拷贝)
  • 零基础学前端-传统前端开发(第三期-CSS介绍与应用)
  • 【报错】【docker】write /opt/test/Model.gguf: no space left on device
  • 飞书多维表格利用 Amazon Bedrock AI 能力赋能业务
  • GlusterFS概述
  • 鸿蒙新闻应用全链路优化实践:从内核重构到体验革新
  • JavaEE-发展历史
  • AI Agent核心技术深度解析:Function Calling与ReAct对比报告