Node.js 学习的第三天,我们将深入学习 Express 框架

1.1 Express 框架简介

Express 是 NodeJS 开发中一个非常重要的第三方框架,对于 NodeJS 服务端的意义,如同 Jquery 对于 HTML 客户端一样,极大地简化了开发流程。它由 TJ 创建,TJ 在 Node 社区声名远扬,创作过 200 多个框架,不过目前他已不再维护 NodeJS 框架,转而投身 Go 语言开发 。Express 官网对自身的定义为:基于 Node.js 平台,快速、开放、极简的 web 开发框架。它最大的亮点在于,不仅保留了 nodejs 原有的所有特性,还在此基础上进行了功能拓展。这意味着,在使用 Express 时,你既能够调用 nodejs 原生的任何 API,也可以使用 Express 自身提供的 API 。例如,第二天所讲的使用 nodejs 实现静态服务器功能,在 express 中仅需一行代码便可完成,而且 express 自带路由功能,让 Node 服务端开发变得更加便捷。同时,express 支持链式语法,能使代码结构更加简洁。Express 最核心的技术与思想,便是 "万物皆中间件"。虽然中间件的概念理解起来稍有难度,但实际使用却非常方便,类似于 jquery 的插件,当 jquery 库自身功能无法满足开发需求时,可借助插件进行功能扩展 。

1.2 Express 框架使用

1.2.1 实现静态服务器功能

回顾第二天使用原生 Node.js 实现静态服务器功能,代码相对复杂。而在 Express 中,实现同样功能非常简单。例如,假设我们有一个名为www的文件夹,里面存放着需要托管的静态资源文件(如 HTML、CSS、JavaScript 文件等)。使用 Express 实现静态服务器功能的代码如下:

js 复制代码
const express = require('express');
const app = express();
// 托管静态资源,__dirname表示当前文件所在的目录
app.use(express.static(__dirname + '/www')); 
const port = 3000;
app.listen(port, () => {
    console.log(`Server running at http://127.0.0.1:${port}`);
});

上述代码中,express.static是 Express 提供的中间件,用于托管静态文件。通过这一行代码,就可以将www文件夹下的所有文件作为静态资源对外提供访问 。

1.2.2 路由功能

Express 自带强大的路由功能,这使得我们无需在一个方法中处理所有请求,能够将不同的请求分发给不同的路由处理函数。例如,对于一个英雄管理系统,可能有获取英雄列表、新增英雄、删除英雄等不同的请求,我们可以为每个请求定义不同的路由。假设我们要处理获取英雄列表的请求,代码如下:

js 复制代码
const express = require('express');
const app = express();
// 定义获取英雄列表的路由,路径为/hero/all,请求方式为get
app.get('/hero/all', (req, res) => {
    // 这里假设从数据库获取英雄列表数据,暂时用一个假数据代替
    const heroList = [
        { id: 1, name: 'Superman' },
        { id: 2, name: 'Batman' }
    ];
    res.send({ data: heroList });
});
const port = 3000;
app.listen(port, () => {
    console.log(`Server running at http://127.0.0.1:${port}`);
});

在上述代码中,app.get用于定义一个 GET 请求的路由,第一个参数/hero/all是路由路径,第二个参数是处理该请求的回调函数。当客户端发起/hero/all的 GET 请求时,服务器会执行这个回调函数,将英雄列表数据返回给客户端 。

1.2.3 第三方中间件使用

在实际开发中,我们经常需要使用第三方中间件来扩展 Express 的功能。使用第三方中间件的步骤一般较为固定,分为两步:

  1. 安装:使用npm i xxxx命令进行安装,这里的xxxx是具体的第三方中间件名称。例如,要安装用于解析 post 请求参数的body - parser中间件,命令为npm install body - parser 。所有的第三方中间件都需要通过 npm 进行安装,可以将其理解为一种特殊的第三方模块。
  1. 使用:安装完成后,在代码中使用app.use(xxx)来启用中间件,具体的使用方式需要参考中间件的官方文档。以body - parser为例,使用代码如下:
js 复制代码
const express = require('express');
const app = express();
// 导入body - parser模块
var bodyParser = require('body - parser');
// 使用body - parser中间件,设置extended为false表示使用简单的语法解析urlencoded数据
app.use(bodyParser.urlencoded({ extended: false })); 
app.post('/abc', (req, res, next) => {
    console.log(req.body);
    // 将接收到的post请求参数返回给客户端
    res.send(req.body);
});
app.post('/efg', (req, res, next) => {
    console.log(req.body);
    res.send(req.body);
});
const port = 3000;
app.listen(port, () => {
    console.log(`Server running at http://127.0.0.1:${port}`);
});

使用body - parser中间件后,req对象会增加一个body属性,该属性存储了客户端通过 post 请求发送过来的参数 。

2. Express 项目实战 - heroAdmin 后台管理系统

2.1 项目介绍

通过本项目,我们将深入了解 Express 搭建服务端项目的完整流程,包括:

  1. 导入 express:在项目中引入 Express 框架,这是使用 Express 的第一步。
  1. 创建服务器:通过express()方法创建一个 Express 应用实例,即服务器。
  1. 配置中间件:根据项目需求,使用各种中间件来增强服务器功能,如前面提到的express.static用于托管静态资源,body - parser用于解析 post 请求参数等。
  1. 路由:定义不同的路由来处理客户端的各种请求,实现不同的业务逻辑,如获取英雄列表、新增英雄、删除英雄等。
  1. 开启服务器:使用app.listen()方法启动服务器,监听指定端口,等待客户端请求 。

同时,我们还需要了解服务端路由处理流程,即:

  1. 请求:获取客户端发送过来的参数,包括请求方法(GET、POST 等)、请求路径、请求体中的数据等。
  1. 处理:根据请求内容,执行相应的业务逻辑,通常涉及对数据库的增删改查操作。在本项目中,我们会操作提前准备好的数据库文件(位于model文件夹中)来管理英雄数据。
  1. 响应:将数据库操作结果或其他处理结果返回给客户端,告知客户端请求处理的情况 。

另外,本项目还涉及服务端接收文件的流程,我们将使用express - fileupload中间件来实现这一功能 。在之前学习 ajax 时,我们通过综合案例hero_admin了解了前端 ajax 实现增删改查的业务逻辑,而在 Node.js 阶段,通过实现hero_admin案例的后台,我们将深入理解服务端增删改查的业务逻辑 。

2.2 项目准备工作

  1. 复制前端代码:将 ajax 最后一天案例hero_admin中写好的前端代码复制粘贴到www文件夹中,该文件夹的作用是托管静态资源,使得前端页面能够正常访问和展示 。
  1. 复制相关文件夹:将课程资料中的model文件夹和static文件夹复制粘贴到项目中。其中,model文件夹存放数据库文件(在本阶段,我们先专注于了解后台工作流程,数据库使用提前编写好的文件),static文件夹用于存储用户上传的图片 。
  1. 安装第三方模块
    • 初始化 npm:在项目根目录下执行npm init -y命令,该命令会快速生成一个package.json文件,用于管理项目的依赖和其他相关信息 。
    • 安装express与body - parser:执行npm i express body - parser命令,npm支持一次性安装多个模块,模块之间使用空格隔开。express是我们项目的核心框架,body - parser用于解析 post 请求参数,这两个模块是项目运行必不可少的 。

在项目中,我们还需要了解一些服务器相关的说明和接口信息,如下表所示:

服务器说明 作用描述
http://127.0.0.1:4399 服务器基地址
200 请求成功状态码
201 新增成功状态码
202 编辑成功状态码
204 删除成功状态码
500 服务器内部错误状态码
接口名称 URL 请求方式 请求参数 返回值
查询英雄列表 /hero/all get (data:{英雄列表})
删除英雄 /hero/delete get id {code:204}
新增英雄 /hero/add post - -

2.3 项目功能实现

2.3.1 完成首页查询英雄列表

在app.js(假设项目的主文件名为app.js)中添加如下代码来实现查询英雄列表功能:

js 复制代码
const express = require('express');
const app = express();
// 假设这里有一个函数用于从数据库获取英雄列表,暂时先写一个假函数
function getHeroListFromDB() {
    return [
        { id: 1, name: 'Wonder Woman' },
        { id: 2, name: 'Spider - Man' }
    ];
}
app.get('/hero/all', (req, res) => {
    const heroList = getHeroListFromDB();
    res.send({ data: heroList });
});
const port = 4399;
app.listen(port, () => {
    console.log(`Server running at http://127.0.0.1:${port}`);
});

上述代码中,getHeroListFromDB函数模拟从数据库获取英雄列表数据,在实际项目中,需要替换为真实的数据库查询代码。app.get('/hero/all', (req, res) => {})定义了查询英雄列表的路由,当客户端发起/hero/all的 GET 请求时,服务器会调用该路由处理函数,获取英雄列表数据并返回给客户端 。

2.3.2 完成新增英雄(难点:nodejs 如何接收客户端 formdata 上传的文件)

要实现新增英雄功能,并且处理客户端通过formdata上传的文件(例如英雄图片),我们需要使用express - fileupload中间件。首先安装该中间件:npm install express - fileupload 。然后在代码中使用:

js 复制代码
const express = require('express');
const fileUpload = require('express - fileupload');
const app = express();
app.use(fileUpload());
app.post('/hero/add', (req, res) => {
    if (req.files) {
        const file = req.files.heroImage; // 假设前端上传的文件字段名为heroImage
        const newFileName = Date.now() + '-' + file.name;
        file.mv(`static/${newFileName}`, (err) => {
            if (err) {
                return res.status(500).send(err);
            }
            // 这里假设新增英雄数据到数据库的函数,暂时先不实现具体数据库操作
            const newHero = {
                name: req.body.heroName,
                image: newFileName
            };
            res.send({ code: 201, message: '英雄新增成功', hero: newHero });
        });
    } else {
        res.status(400).send('没有上传文件');
    }
});
const port = 4399;
app.listen(port, () => {
    console.log(`Server running at http://127.0.0.1:${port}`);
});

在上述代码中,app.use(fileUpload())启用了express - fileupload中间件。在/hero/add的 POST 请求处理函数中,首先检查req.files是否存在,若存在则表示有文件上传。获取上传的文件对象,为文件生成一个新的文件名(这里使用当前时间戳加上原文件名),然后使用mv方法将文件移动到static文件夹中保存。假设新增英雄数据到数据库的操作在后续会完善,这里只是简单构造了一个新英雄对象并返回给客户端新增成功的信息 。

2.3.3 完成根据 id 查询英雄详情

继续在app.js中添加代码实现根据 id 查询英雄详情功能:

js 复制代码
const express = require('express');
const app = express();
// 假设这里有一个函数用于从数据库根据id获取英雄详情,暂时先写一个假函数
function getHeroDetailFromDB(id) {
    const heroList = [
        { id: 1, name: 'Captain America', image: 'captain - america.jpg' },
        { id: 2, name: 'Iron Man', image: 'iron - man.jpg' }
    ];
    return heroList.find(hero => hero.id === id);
}
app.get('/hero/detail', (req, res) => {
    const id = parseInt(req.query.id);
    const heroDetail = getHeroDetailFromDB(id);
    if (heroDetail) {
        res.send({ data: heroDetail });
    } else {
        res.status(404).send('未找到该英雄');
    }
});
const port = 4399;
app.listen(port, () => {
    console.log(`Server running at http://127.0.0.1:${port}`);
});

上述代码中,getHeroDetailFromDB函数模拟从数据库根据 id 查询英雄详情,实际项目中需替换为真实数据库查询代码。app.get('/hero/detail', (req, res) => {})定义了根据 id 查询英雄详情的路由,从客户端请求的查询参数中获取id,调用getHeroDetailFromDB函数获取英雄详情数据,若找到则返回给客户端,若未找到则返回 404 状态码及提示信息 。

相关推荐
宝耶6 分钟前
HTML:表格数据展示区
前端·html
程序员海军20 分钟前
一键把网站变成吉卜力风格的神器来了
前端·chatgpt
三原21 分钟前
前端微应用-乾坤(qiankun)原理分析-沙箱隔离(js)
前端·架构·前端框架
IT专家-大狗23 分钟前
Edge浏览器安卓版流畅度与广告拦截功能评测【不卡还净】
android·前端·edge
Kx…………33 分钟前
Day3:个人中心页面布局前端项目uniapp壁纸实战
前端·学习·uni-app·实战·项目
肠胃炎36 分钟前
认识Vue
前端·javascript·vue.js
七月丶38 分钟前
🛠 用 Node.js 和 commander 快速搭建一个 CLI 工具骨架(gix 实战)
前端·后端·github
砖吐筷筷40 分钟前
我理想的房间是什么样的丨去明日方舟 Only 玩 - 筷筷月报#18
前端·github
七月丶41 分钟前
🔀 打造更智能的 Git 提交合并命令:gix merge 实战
前端·后端·github
iguang42 分钟前
通过实现一个mcp-server来理解mcp
前端