Nodejs 第二十九章 express基础使用

Nodejs 第二十九章 express基础使用

什么是 Express?

Express 是一个灵活的 Node.js Web 应用框架,提供了一套丰富的功能用于构建单页、多页以及混合网页应用。它被设计为使服务器端开发变得快捷而简单,是最流行的 Node.js 框架之一,形成了庞大的生态系统。

为什么需要 Express?

  1. 简化路由和中间件的实现 :Node.js 的原生 HTTP 模块功能强大但不够直观,Express 提供了一个简洁的方式来处理路由,并通过中间件来处理 HTTP 请求和响应。这样开发者就可以方便地定义路由的处理逻辑,对于不同的URL和HTTP方法执行相应的代码。
  2. 提高开发效率:Express 提供了基础的Web开发框架结构,能够快速的起一个项目,避免从零开始编写重复的设置和配置代码。它还支持多种模板引擎,简化视图的生成过程。
  3. 便于集成各种中间件:Express 的设计允许开发者通过中间件来扩展其功能。例如,可以轻松添加体积较小的组件来处理静态文件、会话、用户认证、安全头部等。
  4. 强大的社区支持和资源:由于其广泛的使用,Express 拥有一个庞大的社区,提供大量的资源、文档、教程和第三方库,这对于解决开发中的问题非常有帮助。

Express为当前环境做出的改变

  1. 设置Web开发标准:Express 设定了Node.js Web开发的实践标准,许多其他框架和库也建立在Express的基础之上或受其启发。
  2. 促进了Node.js的普及:Express 作为 Node.js 的一部分,极大地推动了 Node.js 的普及。它的简洁和高效使得 Node.js 成为一个强大的解决方案,适合构建从小型项目到大型企业级应用。
  3. 微服务架构的支持:Express 的轻量级和模块化特性使其成为构建微服务架构应用的理想选择。开发者可以构建独立的服务,每个服务都使用 Express 快速开发,然后通过 RESTful API 或其他方式集成。
  4. 推动了全栈JavaScript的发展:Express 的普及加速了JavaScript全栈开发的趋势,即前后端都使用JavaScript语言。这种模式对于全栈开发者来说降低了学习曲线,项目管理变得更加高效。

初始化项目

  • 在开始正式使用之前,我们需要创建一点文件,我会说明这些文件以及文件夹的作用的

    1. middleware文件夹:用来写中间件的
    2. src文件夹:我们的路由模块源码,我们的主要编写代码就在这里,比如说用户接口的模块,用户登录模块,我们就拆成一个个模块化,结构更清晰
    3. app.js文件:主文件,也相当于入口文件。可以简单的理解为像vite或者webpack起一个项目中的index.html
    4. express.http文件:我们等下就在这里发送请求
  • 解决好了这些之后,我们就可以开始准备使用express了,首先,我们先安装一下~
css 复制代码
 npm i express
  • 然后我们进行简单的使用一下
javascript 复制代码
 import express from "express"
 ​
 //由于express是一个函数,所以我们需要先进行调用一下再进行使用
 const app = express()
 ​
 //参数1:路由路径
 //参数2:回调函数,处理客户端发送过来的请求(拿到发送的内容以及要返回的内容)
 app.get('/get',(req,res)=>{
   res.send('这是get请求')
 })
 ​
 //跟get方法一样的用法
 app.post('/post',(req,res)=>{
   res.send('这是post请求')
 })
 ​
 app.listen(3000,()=>{
   console.log("3000端口成功启动");
 })
  • 通过测试模拟发送客户端请求,我们的两个demo案例接口也是成功的返回了内容,完成了最小案例闭环

动态参数定义

动态参数在路由定义中提供了显著的灵活性和扩展性。它们允许一个路由模式处理多种请求,极大减少了代码重复性,并简化了路由管理。这种方法能有效地降低路由数量,使得应用更易维护,同时提高开发效率。此外,动态参数支持 RESTful API 设计,使得每个URL可以精确地代表一个资源实例,增强了API的直观性和易用性。

  • 如果你暂时不理解这句话什么意思的话,我们就从实践中出发来看看
javascript 复制代码
 // 动态参数
 app.post('/user/:id', (req, res) => {
   res.send('用户页面-动态参数')
 })
  • 动态参数在我们原有定义路由的基础上往后添加内容时,带上冒号:,而附在冒号后面的内容将不再固定(可以随意取名,因为此时起到的占位符的作用)

    • 通过下图,我们请求的是/user/1,这个内容不管是1还是2亦或者是其他内容都是能够触发我们/user开头的接口的
    • 这样的写法很容易进行复用,我们将基于user功能的其他内容继续封装起来,就可以少写很多的内容。这个思想其实是很类似于Class类的继承。是编程思想的一种体现

接收请求内容

  • 在之前使用http模块的时候,我们直接req.xxx就能够拿到了内容。而在express中,也是这种的形式,但也有一点区别

    1. get请求:req.query
    2. post请求:req.body
    3. 动态参数:req.params
  • 也是非常的通俗易懂啊,那就让我们基于以上基础的代码来进行验证一下吧

javascript 复制代码
 app.get('/get', (req, res) => {
   console.log(req.query);
   res.send('这是get请求')
 })
 ​
 app.post('/post', (req, res) => {
   console.log(req.body);
   res.send('这是post请求')
 })
 ​
 // 动态参数
 app.post('/user/:id', (req, res) => {
   console.log(req.params);
   res.send('用户页面-动态参数')
 })
  • 但这里需要注意一下POST请求有点不一样,当我们在进行POST请求,想要拿到JSON数据的时候,我们必须使用express的一个中间件来解析JSON数据。否则拿到的就是一个undefined未定义

    • 中间件是什么?

      中间件我认为就是使用过程安装的插件,我们能够选择的插件是多种多样的。如果从一开始就直接全部默认加载上了,那会非常的臃肿,我们为了轻量化,在有用到的时候在进行挂载,利用效率就很高

      记得把这个app.use()中间件放到前面,因为代码按顺序加载的,如果使用在前、挂载在后,那就是马后炮的作用

less 复制代码
 app.use(express.json())

模块拆分

  • express的基础使用我们已经熟悉了,但在正常的开发中,我们是不可能这么写的,因为要编写的接口很多。如果所有的接口都挤在app.js这个文件的话,就算有添加详细的注释,也很难维护,没办法清晰的明白我们项目的结构
  • 所以,我们现在要将一个个接口给拆分出去了,根据不同的功能进行分组
  • 此时要用到的就是express中的Router模块了,我使用了两个案例接口来演示。一个是登录注册接口,一个是图片接口。现在让我们来试试吧!
javascript 复制代码
 //user.js文件(登录注册接口)
 import express from "express"
 ​
 const Router = express.Router()//路由模块
 ​
 Router.post('/login', (req, res) => {
   //我们返回的是json格式的数据,express路由中有提供对应的方法
   res.json({
     code:200,
     msg:'登录成功'
   })
 })
 ​
 Router.post('/register', (req, res) => {
   res.json({
     code:200,
     msg:'注册成功'
   })
 })
 ​
 ​
 export default Router
javascript 复制代码
 //picture.js文件(图片接口)
 import express from "express"
 ​
 const Router = express.Router()
 ​
 Router.get('/jpg',(req,res)=>{
   res.json({
     code:200,
     msg:'返回jpg图片列表',
     data:[{
       '落叶':'https://cdn.pixabay.com/photo/2024/03/04/16/44/barberry-8612696_1280.jpg',
       '狗':'https://cdn.pixabay.com/photo/2024/01/07/11/17/welsh-corgi-8492879_1280.jpg',
       '猫咪':'https://cdn.pixabay.com/photo/2023/12/08/23/46/cat-8438334_1280.jpg'
     }]
   })
 })
 ​
 Router.get('/png',(req,res)=>{
   res.json({
     code:200,
     msg:'返回png图片列表',
     data:[{
       '代码':'http://tuchuang.xiaoyu2002.cn/picture/image-20240427191716914.png',
       '二次元美少女':'https://p6.itc.cn/q_70/images01/20230426/aebe488ff7e14e538c464994efb35486.png'
     }]
   })
 })
 ​
 export default Router
  • 然后我们在app.js文件中进行导入

    • 通过这里,我们能够看到内容还是非常清爽的,一下子就简洁了很多
javascript 复制代码
 import express from "express"
 import picture from "./src/picture.js"
 import user from "./src/user.js"
 ​
 const app = express()
 app.use(express.json())
 // 路由接口,前面加上前缀就是为了防止我们路由接口的重名问题,目录也更清晰
 app.use('/picture',picture)
 app.use('/user',user)
 ​
 app.listen(3000, () => {
   console.log("3000端口成功启动");
 })

Picture接口返回内容测试(GET)

user接口返回内容测试(POST)

  • 通过上面模块化的拆分测试,也是都明显成功了,每个文件里面都有两个接口,都能成功进行请求并返回正确内容。这是express的一个核心的功能点

中间件的编写

中间件是一个关键概念。中间件是处理HTTP请求和响应的函数,它位于请求和最终路由处理函数之间,可以对请求和响应进行修改、执行额外的逻辑或者执行其他任务。

中间件函数接收三个参数:req(请求对象)、res(响应对象)和next(下一个中间件函数)。通过调用next()方法,中间件可以将控制权传递给下一个中间件函数。如果中间件不调用next()方法,请求将被中止,不会继续传递给下一个中间件或路由处理函数

  • 除了Router这个核心的模块化拆分功能之外,中间件也是Express同等重要的核心功能

    • 在前面中,我们就有使用过来自express的json中间件。那现在就来让我们自己探究一下内部的奥秘吧!
    • 还记得我们一开始创建的middleware(英译:中间件) 文件夹吗?我们在这里进行编写一个简单的中间件来走通流程
  • 此时我们会用到log4js这个第三方库,所以记得npm安装一下

    安装命令:npm i log4js

    • 按照我们的习惯,我们在进行使用一个第三方库的时候,也要稍微了解一下这个库是用来做什么的

log4js日志第三方库

Log4js 是一个流行的 Node.js 日志库,它是基于 Java 的 Log4j 库的思想设计的。这个库提供了灵活的日志记录解决方案,适用于 Node.js 应用程序,支持多种日志记录方式和配置选项,让开发者能够有效地控制日志的格式、目的地和级别。

核心特性

  1. 多种日志级别

    • Log4js 支持标准的日志级别,如 TRACE, DEBUG, INFO, WARN, ERROR, 和 FATAL。这样可以根据信息的重要程度来区分日志消息。
  2. 多种输出方式

    • 支持多种输出目的地(称为 appenders),如控制台、文件、远程HTTP服务器等。你可以配置多个输出目的地,根据不同的日志级别或者格式发送到不同的存储介质。
  3. 灵活的配置选项

    • Log4js 的配置非常灵活,可以通过 JSON 或 JavaScript 对象进行配置。这包括定义不同的日志级别,设置日志的格式,以及指定哪些记录器(logger)应该使用哪些输出器(appender)。
  4. 日志分类

    • 支持创建多个不同的记录器实例,每个记录器可以有其特定的配置。这对于大型应用来说非常有用,可以为不同的系统组件或模块创建专门的日志记录器。
  5. 日志滚动

    • 支持文件日志滚动,这意味着可以配置日志文件在达到特定大小或者时间后自动滚动(归档),避免单个日志文件过大。

应用场景

  • 开发调试:使用较低级别的日志(如DEBUG)帮助开发者了解应用的运行流程。
  • 错误跟踪:在生产环境中使用ERROR或FATAL级别记录关键错误,便于迅速定位问题。
  • 性能监控:记录关键操作的处理时间,帮助分析和优化性能瓶颈。
  • 用户行为跟踪:记录用户的关键操作,用于分析用户行为模式或进行审计。
  • 接着具体如何使用,我们就在接下来的这个中间件案例进行尝试吧!

初始化中间件

  • 中间件是有他的使用方式的,也就是req,res,next三件套,组成了最基础的模板,通过文字可以不够直观,看通过代码我们一定能够一览无遗

    • 很明显中间件 是一个函数,我们在函数中调用next()来决定是否把控制权递交到下一个中间件的手里,并且可以传递一个错误参数给它,如果传递错误参数,则 Express 会跳过后续的所有非错误处理中间件,直接移交给错误处理中间件,也就是next(err)
javascript 复制代码
 import log4js from "log4js"
 ​
 // req:接收前端发送过来的信息
 // res:返回给前端的内容
 // next:决定是否执行下一个中间件,如果不写就一直卡在这里
 const loggerMiddleware  = (req,res,next)=>{
   // 中间件内容
   next()
 }
 ​
 export default loggerMiddleware
  • 接着我们通过log4js来实现日志效果

    • 在 log4js 和其他许多日志系统中,appender 是一个非常重要的概念。Appender 是日志处理流程中的一个组件,它负责控制日志数据的输出目的地和输出方式。换句话说,appender 定义了日志消息如何被记录和存储。每个 appender 可以指定不同的输出目标,例如文件、数据库、控制台或者远程服务器等
    • 我们在这里一共要实现两个功能,一个是控制台打印日志,另外一个则是写入日志文件。都是非常常见的功能。我们这两个功能都在appenders选项中进行配置,然后在categories选项中放入defalut配置中,这也是我们后面调用getLogger方法的由来,把我们配置两个功能设为默认功能,然后加载默认功能,这是一个不断集成的过程
go 复制代码
 // 配置 log4js 日志库
 log4js.configure({
   appenders: {  // 定义日志输出的目的地,即日志的存储方式
     out: {  // 定义一个名为 'out' 的 appender
       type: 'stdout', // 指定输出类型为标准输出(控制台)
       layout: {  // 定义日志输出的布局格式
         type: 'colored' // 使用带颜色的布局,使控制台输出带有颜色区分,便于阅读
       }
     },
     file: {  // 定义一个名为 'file' 的 appender
       type: 'file', // 指定输出类型为文件
       filename: './logs/server.log', // 设置日志文件的存储路径和文件名
     }
   },
   categories: {  // 定义日志的分类
     default: {  // 配置默认类别的日志属性
       appenders: ['out', 'file'], // 此类别的日志将使用名为 'out' 和 'file' 的 appender 输出
       level: 'debug' // 设置此类别的日志记录级别为 debug(记录所有debug及以上级别的日志)
     }
   }
 });
 ​
 // 获取 logger
 //在 log4js 中,getLogger 方法用于创建或获取一个日志记录器(logger)对象。这个对象提供了接口来记录日志消息,可以指定不同的日志级别,如 debug, info, warn, error, 等
 const logger = log4js.getLogger('default');
  • 通过这些配置然后放入我们的中间件就能进行使用了
javascript 复制代码
 // 日志中间件
 const loggerMiddleware = (req, res, next) => {
   logger.debug(`${req.method} ${req.url}`); // 记录请求方法和URL
   next();
 };
  • 最终在app.js文件中进行挂载,让我们来看看效果
javascript 复制代码
 // 导入中间件
 import loggerMiddleware from './middleware/logger.js'
 // 使用我们自己写的中间件
 app.use(loggerMiddleware)
  • 能够看到,不仅在控制台成功输出相关的内容了,而且创建了日志文件并写入相关的内容

完整中间件代码

javascript 复制代码
 import log4js from "log4js"
 ​
 // 配置 log4js 日志库
 log4js.configure({
   appenders: {  // 定义日志输出的目的地,即日志的存储方式
     out: {  // 定义一个名为 'out' 的 appender
       type: 'stdout', // 指定输出类型为标准输出(控制台)
       layout: {  // 定义日志输出的布局格式
         type: 'colored' // 使用带颜色的布局,使控制台输出带有颜色区分,便于阅读
       }
     },
     file: {  // 定义一个名为 'file' 的 appender
       type: 'file', // 指定输出类型为文件
       filename: './logs/server.log', // 设置日志文件的存储路径和文件名
     }
   },
   categories: {  // 定义日志的分类
     default: {  // 配置默认类别的日志属性
       appenders: ['out', 'file'], // 此类别的日志将使用名为 'out' 和 'file' 的 appender 输出
       level: 'debug' // 设置此类别的日志记录级别为 debug(记录所有debug及以上级别的日志)
     }
   }
 });
 ​
 // 获取 logger
 //在 log4js 中,getLogger 方法用于创建或获取一个日志记录器(logger)对象。这个对象提供了接口来记录日志消息,可以指定不同的日志级别,如 debug, info, warn, error, 等
 const logger = log4js.getLogger('default');
 ​
 // req:接收前端发送过来的信息
 // res:返回给前端的内容
 // next:决定是否执行下一个中间件,如果不写就一直卡在这里
 const loggerMiddleware  = (req,res,next)=>{
   logger.debug(`${req.method} ${req.url}`); // 记录请求方法和URL
   next()
 }
 ​
 export default loggerMiddleware
  • 以及完整的测试发送请求代码
shell 复制代码
 # get请求
 # GET http://localhost:3000/get?a=1&b=2 HTTP/1.1
 ​
 # post请求
 # POST http://localhost:3000/post HTTP/1.1
 # Content-Type: application/json
 ​
 # post请求(动态参数)
 # POST http://localhost:3000/user/1 HTTP/1.1
 # Content-Type: application/json
 ​
 # post请求 带JSON数据
 # POST http://localhost:3000/post HTTP/1.1
 # Content-Type: application/json
 ​
 # {
 #   "name":"小余"
 # }
 ​
 # picture接口请求
 GET http://localhost:3000/picture/jpg HTTP/1.1
 # GET http://localhost:3000/picture/png HTTP/1.1
 ​
 ​
 # user接口请求
 # POST http://localhost:3000/user/login HTTP/1.1
 # POST http://localhost:3000/user/register HTTP/1.1
  • 通过动手实践,我们亲自完成了express的基础使用、动态定义参数、模块化的使用路由以及完整的实现了一遍日志中间件的编写,我相信在学习的路上,我们会坚持到最后,看到山顶的风光
相关推荐
熊的猫5 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn11 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
四喜花露水44 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust2 小时前
css:基础
前端·css
帅帅哥的兜兜2 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
工业甲酰苯胺2 小时前
C# 单例模式的多种实现
javascript·单例模式·c#
yi碗汤园2 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称2 小时前
购物车-多元素组合动画css
前端·css