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

chapter6 express

在前文,我们利用node的原生语法编写了一些简单的node应用,具备基本的请求处理与返回,但这样的处理有一些繁琐,因此,我们可以利用第三方的框架来简化这一系列操作,本文通过整合express框架,来简化node应用的开发流程。

express.js

Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具,因其语法简洁,开发效率高而流行。

express架构模式

Express 的核心架构是基于 中间件(Middleware)链式调用 模式构建的,也称为 “洋葱模型”“职责链模式”,这种设计可以方便的进行各种单一职责的模块的开发,并且十分利于工具的复用,它的核心为以下两个方法:

  • app.use:应用中间件
  • next():链接到下一个中间件

express安装

通过npm等包管理器来进行安装:

npm install express

express还提供了一系列的中间件,同express一起安装:

  • body-parser - node.js 中间件,处理 JSON, Raw, Text 和 URL 编码的数据。
  • cookie-parser - 解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
  • multer - node.js 中间件,处理 enctype="multipart/form-data"(设置表单的MIME编码)的表单数据。

express基本语法

在一个express应用中,程序是以app的实例化来开始的:

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

同原生的node语法类似,但express提供了更加简洁的语法(如路由、请求/响应等),下面我们来学习它

路由

相对于传统的node路由编写,express提供了更加简洁的方式,通过对应的请求方法来注册路由:

const express=require('express')
const app=express()//实例化一个express对象
app.get('/',function(req,res){//注册一个/路由,当访问服务器时就会处理
res.send("hello express")
})
//路由也可以接收不同的请求类型
app.post('/send',function(req,res){
res.send('这是一个post请求')
})
const server=app.listen(8088,function(){//初始化服务器
console.log("http://localhost:8088")
})
app.use('/a')//注册中间件路由,一般用于执行一些判断逻辑,如权限、角色、cookie的校验

请求与响应

在express中,请求与响应通过request与response对象的一系列方法与属性来实现,与原生node语法近似,但更为简洁:
例如,我们想发送一个响应,在node原生中是这样的:

res.writeHead(200,{
'Content-Type':'text/plain;charset=utf-8'
})//首先设置响应头
res.end('abc')//发送响应

在express,它可以简化为send:

res.send('abc')//发送响应

可以看到,在express中我们没有显式的设置头,因为在express中,它会根据send的传参类型自动判断响应类型,保证浏览器能够解析标签,从而省去冗杂的样板代码。
下面,我们来介绍一下常用的方法:

常用方法

  • request(统一简写为req):
  1. req.params:路由参数对象,键值对形式,一般用于GET/POST中获取参数,如路由 /user/:idreq.params.id
  2. req.query:URL 查询字符串参数对象,解析后的键值对,/search?kw=expressreq.query.kw
  3. req.body:请求体数据(需配合 body-parser 或内置中间件)。可以读取 JSON、表单、Raw、Buffer 等。
  4. req.headers:原始请求头数据
  5. req.get(headerName):获取指定请求头字段值,如获取头中cookie
  6. req.cookies:解析后的 Cookie 对象(需配合 cookie-parser 中间件)。
  7. req.signedCookies:解析并验证签名后的 Cookie(需配合 cookie-parser 且使用了签名)。
  8. req.path:- 请求 URL 的路径部分,不包含查询字符串。
  9. req.accepts():检查可接受的请求的文档类型
  10. req.route:当前匹配的路由
  • Response(简写为res)
  1. res.status(code):设置响应码,如常见的200/400/403/500/502.....
  2. res.send:发送响应体,可以是 Buffer、字符串、对象(会自动转 JSON 并设置 Content-Type),是最常用的方法
  3. res.json:发送json响应,一般在前后端分离模式中常用
  4. res.render(view[, locals][, callback]):渲染模版,node集成模版引擎时才使用
  5. res.redirect([status,] path):重定向到url
  6. res.format(obj):根据请求头,格式化响应体,如html则格式化响应体为html,text则text等等.....
  7. res.set(field[, value]):设置响应头
  8. res.get(field):获取响应头
  9. res.type(type):设置响应类型
    • res.attachment([filename]) 设置 Content-Disposition: attachment,可指定下载文件名。
  10. res.download(path[, filename][, options][, fn]) :提示客户端下载本地文件,内部调用 res.sendFile() 并设置为附件。
  11. res.cookie(name, value[, options]) 设置 Cookie,支持签名、过期、路径、域名、安全等选项。
  12. res.clearCookie(name[, options]):清除 Cookie,效果相当于设置一个过期日期为过去的 Cookie。
  13. res.append(field, value):追加信息到响应头

静态文件

当需要进行html的页面渲染时,则需要使用express内置的中间件 express.static 来设置静态文件,可以通过app.use来注册一个中间件函数实现:

express=require('express')
app=express()
app.use('/a',express.static('st'))//假设文件存放在st目录下
const server=app.listen(8077,function(req,res){
console.log('http://localhost:8077')
})

当我们输入http://localhost:8077/a/文件名时,就可以直接访问到这些静态文件。

表单提交

在web程序中,我们应用最多的场景一般是各种表单的提交(搜索、登录、注册....),node因为借助于js实现,因此可以方便的联动前端来实现:
我们需要先准备一个表单页面form.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Form提交</title>
</head>
<body>
    <header>
        <h1>Submit Your Details</h1>
    </header>
    <main>
        <form action="/submit" method="POST">
            <label for="name">姓名:</label>
            <input type="text" id="name" name="name" required><br><br>
            <label for="email">邮箱:</label>
            <input type="email" id="email" name="email" required><br><br>
            <button type="submit">提交信息</button>
        </form>
    </main>
    <footer>
        <p>form测试</p>
    </footer>
</body>
</html>

接着编写服务器test_form.js:

const express = require('express');
const bodyParser = require('body-parser');//引入请求体解析中间件
const app = express();
const port = 3000;
app.use(bodyParser.urlencoded({ extended: true }));//配置请求体解析中间件
app.use(express.static('st'));
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/st/form.html');
});//服务器入口路由返回上文页面
app.get('/index/:id', function (req, res) {
    console.log(req.params.id)
    loe=req.query
    res.send(`id为:${loe.keyword}`)
});
app.post('/submit', (req, res) => {
    const { name, email } = req.body;//从请求中解析出name与email字段
    res.send(`Form submitted! Name: ${name}, Email: ${email}`);//格式化拼接后返回
});
app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

填写表单字段提交后,可以看到name与email的返回,这样就是一个简单的post表单提交,如果我们需要通过id等数据获取内容,则需要使用get请求来进行获取:
修改test_form.js如下:

const express = require('express');
const bodyParser = require('body-parser');//引入请求体解析中间件
const app = express();
const port = 3000;
app.use(bodyParser.urlencoded({ extended: true }));//配置请求体解析中间件
app.use(express.static('st'));
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/st/form.html');
});//服务器入口路由返回上文页面
app.get('/index/:id', function (req, res) {
    const simulatedData = {
        id: 123,
        keyword: 'exampleKeyword'
    };//因为没有数据库,使用模拟数据代替
    console.log(`Simulated Data: id=${simulatedData.id}, keyword=${simulatedData.keyword}`);
    const id = simulatedData.id;
    const keyword = req.query.keyword || simulatedData.keyword;
    console.log(`Request ID: ${id}`);
    res.send(`id为:${keyword}`);
});
app.post('/submit', (req, res) => {
    const { name, email } = req.body;//从请求中解析出name与email字段
    res.send(`Form submitted! Name: ${name}, Email: ${email}`);//格式化拼接后返回
});
app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

在浏览器输入 http://localhost:3000/index/123 可以看到模拟数据的内容。

文件上传处理

在web开发流程中,文件上传是一个常见的场景,express通过中间件来简化文件流的处理:下面我们来实现一段上传与上传成功的消息返回:
upload.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>文件上传</title>
</head>
<body>
  <h2>上传文件</h2>
  <!-- 文件上传表单 -->
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="file" required />
    <button type="submit">上传</button>
  </form>
  <h2>上传结果</h2>
  <!-- 显示上传结果的消息 -->
  <p id="message"></p>
  <script>
    // 检查 URL 参数并显示上传消息
    const params = new URLSearchParams(window.location.search);
    if (params.has('message')) {
      const message = params.get('message');
      document.getElementById('message').textContent = message;
    }
  </script></body></html>

fileload.js:

// 引入 express 模块
const express = require('express');
const multer = require('multer');
const app = express();
const port = 3000;
// 配置中间件解析表单数据
app.use(express.urlencoded({ extended: true }));
// 提供静态文件服务
app.use(express.static('st'));
// 配置 multer 用于文件上传
const upload = multer({ dest: 'st/uploads/' });
// 处理文件上传的路由
app.post('/upload', upload.single('file'), (req, res) => {
    if (req.file) {
        // 如果文件上传成功,重定向到 fileload.html 并显示成功消息
        res.redirect('/fileload.html?message=文件上传成功');
    } else {
        // 如果文件上传失败,显示错误消息
        res.redirect('/fileload.html?message=文件上传失败');
    }
});
// 启动服务器并监听指定端口
app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});

运行后,我们可以看到文件上传成功后有正常的显示,如果我们想实现上传完后的回显,又应该如何处理呢?在常规Node中,我们可能需要手动处理文件流并进行相关返回才能实现该需求,但在express中,我们可以通过express的中间件快速的集成三方库(如multer)来实现图片的上传与回显。
下面是一个express中间件集成multer快速实现图片回显的例子:
首先需要在项目中安装multer:

npm intstall multer

接着我们修改html以应用这些更改:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>文件上传</title>
</head>
<body>
  <h2>上传文件</h2>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <input type="file" name="file" required />
    <button type="submit">上传</button>
  </form>
  <h2>上传结果</h2>
  <img id="preview" src="" style="max-width: 300px; margin-top: 20px;" />
  <script>
    // 检查 URL 参数并回显图片(设置文件路径属性)
    const params = new URLSearchParams(window.location.search);
    if (params.has('filename')) {
      const filename = params.get('filename');
      document.getElementById('preview').src = `/uploads/${filename}`;
    }
  </script>
</body>
</html>

接着编写fileload.js:

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
// 设置静态目录
app.use(express.static('st'));
app.use('/uploads', express.static('uploads'));
// 设置 multer 存储路径与文件名
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads'); // 上传目录
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + path.extname(file.originalname)); // 使用时间戳命名
  },
});
const upload = multer({ storage: storage });
// 处理上传请求
app.post('/upload', upload.single('file'), (req, res) => {
  const filename = req.file.filename;
  res.redirect(`/testload.html?filename=${filename}`);
});
// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`服务器已启动: http://localhost:${PORT}/testload.html`);
});

这样,我们就实现了一个简单的node文件上传回显示例了,当文件上传成功后,node服务器会返回它的路径进行Img的src设置,从而实现一个简单的上传回显。

在web开发中,我们通常需要进行各种表单以及数据的获取与提交,但这些操作大部分是重复的,那么,有没有什么方法能够复用这些操作的数据以带给用户更佳的体验呢?在web开发中,可以使用session/cookie/token来进行这些数据的存储。其中,session由于抗并发能力差,因此在当今的前后端分离架构中使用较少,而cookie因为存储在浏览器上,因此大范围用于存储状态等信息。
node提供了丰富的中间件,可以快速的集成cookie。
首先我们需要安装对应的中间件:

npm install cookie-parser

然后,我们需要在express对其进行中间件注册:

const cookieParser = require('cookie-parser');//引入并实例化
app.use(cookieParser())

在注册之后,我们就可以使用cookieparser来进行cookie的相关操作了,cookieparser的常用操作有三个:

  • res.cookie():设置cookie
  • res.cookies:cookie属性,用于获取cookie
  • res.clearCookie:用于对cookie进行删除
    下面,我们通过一个html+js来实现基本的cookie操作
    cookie.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cookie Demo</title>
</head>
<body>
    <h1>Cookie Demo</h1>
    <button id="setCookie">设置Cookie</button>
    <button id="getCookie">读取Cookie</button>
    <button id="clearCookie">清除Cookie</button>
    <p id="output"></p>
    <script>
        document.getElementById('setCookie').addEventListener('click', () => {
            fetch('/set-cookie')
                .then(response => response.text())
                .then(data => {
                    document.getElementById('output').textContent = data;
                });
        });
        document.getElementById('getCookie').addEventListener('click', () => {
            fetch('/get-cookie')
                .then(response => response.text())
                .then(data => {
                    document.getElementById('output').textContent = data;
                });
        });
        document.getElementById('clearCookie').addEventListener('click', () => {
            fetch('/clear-cookie')
                .then(response => response.text())
                .then(data => {
                    document.getElementById('output').textContent = data;
                });
        });
    </script>
</body>
</html>

cookie.js:

const express = require('express');
const cookieParser = require('cookie-parser');
const path = require('path');
const app = express();
const port = 3000;
// 使用cookie-parser中间件
app.use(cookieParser());
// 定向到cookie_demo.html
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'st', 'cookie_demo.html'));
});
// 设置cookie的路由
app.get('/set-cookie', (req, res) => {
    res.cookie('username', 'testuser', { maxAge: 900000, httpOnly: true });
    res.send('Cookie已设置');
});
// 读取cookie的路由
app.get('/get-cookie', (req, res) => {
    const username = req.cookies['username'];
    if (username) {
        res.send(`Cookie中的用户名是: ${username}`);
    } else {
        res.send('未找到用户名的Cookie');
    }
});
// 删除cookie的路由
app.get('/clear-cookie', (req, res) => {
    res.clearCookie('username');
    res.send('Cookie已清除');
});
app.listen(port, () => {
    console.log(`服务器运行在 http://localhost:${port}`);
});

运行服务器,点击对应的按钮,我们可以看到这三个操作都被触发。

http://www.sczhlp.com/news/2643/

相关文章:

  • 比特彗星常见问题-断网问题
  • 清华大学软件学院长聘副教授龙明盛:Timer 3.0 已经成为了“满血版”的时序大模型
  • request入门与使用
  • 7.31闲话
  • 7.30闲话
  • 关于c++的一些没有用的芝士 - AC-13
  • 搜维尔科技:Tesollo灵巧手推出新款机器人夹持器“DG-3F”
  • 【ESP8266】ESP8266 模块接入Deepseek大模型,实现AI女友的第一步
  • 图论题目总结
  • THUPC 2025 决赛 喜爱之钥
  • 408-OS之管程
  • java语法学习
  • 在 Ubuntu Server 上 使用 USB 无线网卡连接 Wifi
  • 比特彗星常见问题-种子市场使用教程
  • 搜维尔科技:2025年人形机器人动捕技术研讨会将在本周四召开
  • 数据库
  • 第一篇:MySQL数据库介绍及部署
  • Trie
  • React的API:memo
  • 太原
  • 生成函数学习笔记
  • 比特彗星常见问题-意外退出程序后下载列表清空的解决方法
  • 2025“钉耙编程”中国大学生算法设计春季联赛(1)
  • 从日志到告警,带你用好 SeaTunnel 的事件监听能力
  • 14
  • 2025.7.31总结 - A
  • 2025.7.31学习日记
  • 比特彗星常见问题-屏蔽吸血客户端和设置自动反吸血
  • 括号组合全排列
  • rust里的时间控制