后端-Node系列三:Express框架

705 阅读14分钟

Express web框架官网

1: express基础

1.1: express简介

// ------------------------------- express简介 --------------------------------
express是基于node.js封装出来的是专门用来创建web服务器的,本质上就是一个第三方包
express能快速创建web服务器和API接口的服务器

1.2: 使用express创建基本的web服务器

// ----------------------- 使用express创建基本的web服务器 ------------------------
使用express创建web服务器
const express = require('express')
const app = express()
app.listen(80, ()=> {
  console.log('express server runing at http://127.0.0.1')
})

1.3: 监听GET和POST请求以及响应客户端

// -------------------------- 使用express创建get和post请求 -------------------------------
//1: get
app.get('/user, (req, res) => {
   res.send({name: 'zs', age: 20, gender:''})
})
// 2:post
app.post('/user', (req, res) => {
  res.send('请求成功')
})
通过postman 来测试接口, 直接通过请求方式请求接口地址点击send就能在body中打印数据了,不用携带任何参数

2: URL请求地址

2.1:获取URL中携带的查询参数

//------------------------- 获取URL中携带的查询参数 ------------------------------ 
get 方式的req.query查询参数
req.query获取到查询参数
app.get('/', (req, res) => {
   console.log(req.query)
})
在postman中测试接口, 直接在请求地址后面携带参数和在面板中的params中写是一样的, 通过send后他们两都会自动互相填写。 req.query默认是空对象。 如果请求地址携带参数, body中返回的就是send过来的查询参数,是一个对象类型的

2.2:获取URL中的动态参数

获取url中的动态参数id, 通过req.params
app.get('/user/:id', (req, res) => {
   console.log(req.params)
})
通过posman直接在请求地址后面/携带id, 点击send, body就能接收到这个id,不填写时, 默认也是空对象。

2.3:补充动态参数的两个注意点

动态参数名时自己随意取的,你怎么取, 通过url传递参数的时候, 返回来的body就能以键值对的形式将参数名:与参数值,以对象形式,成对展示在控制台中
app.get('/user/:ids/:username', (req, res) => {
  res.send(req.params)
})
postman GET请求: http://127.0.0.1/user/3/zs
body请求体中返回的数据{"id": "3",  "username": "zs"}

3: express.static托管静态资源

3.1: 使用express.static托管静态资源

express.static能指定托管的静态资源的文件夹
1:托管方式:app.use(express.static('要托管的静态资源文件夹'))
2:访问方式:直接在 127.1.0.1/输入要访问的文件
3:页面效果: 就能直接把文件显示在本页面
4:注意细节:app.use(express.static可以指定任意一个文件夹当做静态资源托管, 访问方式不需要携带该托管的文件夹。直接在请求地址后面输入要访问的文件即可)

3.2:托管多个静态资源目录

挂在多个,就多次调用express.static挂几次, 就有几个。 如果挂在的多个文件夹中, 有同名文件, 按照加载顺序。 会从上至下依次加载
举例: express.static('./files') ---->它下面有1个index.html
      express.static('./clock') ----->它下面也有1个index.html
通过 浏览器的url地址访问: 127.0.0.1/index.html 
页面返回的是: ./files/index.html 这个页面, 因为他是按照加载顺序, 只加载前一个

3.3:挂载路径前缀

给托管的静态资源文件夹, 添加前缀名称
语法规则:app.use('/前缀名', express.static('./将哪个文件夹托管为静态文件夹'))
代码示例: app.use('/files', express.static('./files)), 必须有意义,和托管的文件夹名称一致
访问方式: 127.0.0.1/files/index.html
页面效果: 返回的是files下的index.html这个页面

4: 安装nodemon 实现项目的自动重启

安装方式 npm i -g nodemon 全局安装, 一次安装, 终身使用
之前使用的 是 node xx 文件, 现在用 nodemon xx 文件

5:express路由

5.1:express路由概念

// -------------------------- 路由的概念 --------------------------
路由简称对应关系, 映射关系

// -------------------------- 了解express中路由的概念及组成部分 --------------------------
路由就是客户端和服务器处理函数之间的映射关系
由3部分组成: app.请求方式('请求地址', '回调函数')
app.get('/', function(req, res) { res.send('xxx') })
app.post('/', function(req, res) { res.send('xxxx') })

// --------------------------  路由的匹配过程 --------------------------
路由的匹配顺序是从上至下的匹配方式, ,必须满足前2个条件才会执行对应的处理函数。 
满足 app.get('/', function() {}). 满足了get请求方式和请求地址, 才会调用对应的请求处理函数。

5.2:路由最简单的用法

//-------------------------- 路由最简单的用法 ---------------------------------
路由最基础的用法
1: 基础的创建自己的项目: 
1:  创建一个空的英文名称的空项目
2:在项目中初始化, package.json文件: npm init -y
3: 安装最基础的 express包 :  npm i express@4.17.1
4:用nodemon 的方式,挂载服务器: nodemon xx

最基础的路由示例:
app.get('/', (req, res) =>  {res.send('xxx')})
app.post('/', (req, res) => { res.send('xxx')})

postman 发起请求
get 方式 http://127.0.0.1/    body 响应 send中的文本信息
post 方式 http://127.0.0.1/  body响应  send中的文本信息

5.3:express.Router()创建路由模块

// ------------------------- express.Router()创建路由模块 --------------------------------
创建Router对象, 挂载和导出路由对象的使用方式
1: 创建路由对象  : const router = express.Router( )
2:挂载路由请求 :router.get('/user/list', (req, res) => { res.send('xx') })
3:导出路由对象 :module.exports = router

5.4:app.use()注册路由模块

//--------------------------- app.use()注册路由模块 ------------------------------------
如何在别的页面导入和使用别人定义好的路由
因为之前创建好的路由,写好了路由地址,和对外导出了, 我们只需接收挂载即可
1: 导入路由:  const router = require('./03.router.js')
2:挂载路由: app.use(router)
3:postman测试路由: 
get方式, 请求地址: http://127.0.0.1/user/list,响应send中的文本信息
post方式, 请求地址: http://127.0.0.1/user/add , 响应send中的文本信息
总结:只需要通过 文件导入的方式,将导入的文件用常量接收,将常量挂载到app.use上即可

5.5: 为路由模块添加访问前缀

//---------------------------- 如何给路由添加前缀 --------------------------------
1: app.use('前缀名', 接收到的路由对象)
2postman: get方式, http://127.0.0.1/api/user/list, 就能成功响应send中的文本

1: Express中间件

1.1: 中间件的概念

//------------------------- 中间件的概念 ----------------------------
中间件就是中间处理环节
这个处理环节就叫, 中间件, 中间件事有输入和输出的

// -------------------------  express中间件的调用流程 ----------------------------
当一个请求到达express服务器之后, 可以调用多个中间件去进行处理, 中间件是有输入和输出的。 
最终的输出结果会通过服务器响应到客户端

// ----------中间件的格式,就是 next,谁回调函数的第三个参数
中间件的本质就是function处理函数, 他是回调函数的第三个参数,叫next, 
当函数处理完成,需要调用形参next()将处理的结果, 交给下一个中间件去接收。接着处理

// --------------- express中间件的格式 ----------------------------
中间件的格式,就是 next,谁回调函数的第三个参数
中间件的本质就是function处理函数, 他是回调函数的第三个参数,叫next, 当函数处理完成,需要调用形参next()将处理的结果, 交给下一个中间件去接收。接着处理 

//------------------------- next函数的作用 ----------------------------
next( )函数,就相当于交接, 把自己处理好的结果,交接给下一个中间件或者路由, 

//------------------------- 定义中间件函数 ----------------------------
最简单的中间件定义的代码示例
const express = require('express')
const app = express( )
const mw = function(req, res, next) { cosnoel.log('xxx')  next( ) }

2: 全局中间件

2.1:全局生效的中间件

//-------------------- 全局生效的中间件 ------------------------------
只要定义了中间件, 中间件调用了next( )方法, 通过app.use(中间件函数)注册为全局中间件, 这样后面的请求都会出发这个中间件对外输出的内容
1:定义中间件 const mw = function(req, res, next) { next( ) }
2:注册为全局中间件  app.use(mw)
3:发请求测试能否触发全局中间件   app.get('/', (req, res) -> { res.send( xx ) })  
4:postman接口测试:get方式,请求地址:http://127.0.0.1/ body响应 send中的文本
5:终端返回的结果:1:触发了中间件中的内容, 2:触发了自己请求中响应的内容
6:总结:只要将中间件通过app.use注册为全局组件, 后续的每个请求都会触发该中间件。

2.2: 定义全局中间件的简化形式

//--------------------------- 定义全局中间件的简化形式 -------------------------
简化操作:两步合为一步: 直接把中间件挂载注册到app.use身上
绑定app.use注册((req, res, next) => { next( ) })
操作之后,打印的结果是一摸一样的。无任何改变,代码又简化了

2.3:中间件的作用

//---------------------------- 中间件的作用  ------------------------------
中间件在实际开发中的应用场景:
举例: 假设多个请求中都需要处理同一个东西, 何不把这个东西,放在中间件中处理好, 然后将结果还给这2个请求,请求中就你能将中间件的处理结果输出
1: 将共同方法定义在中间件中:app.use((req, res, next) =>{ const time = Date.now( )  req.startTime = time })
2:后续的2个请求,拿到中间件的处理结果:app.get('/user', (req, res) => { res.send('xx' + req.startTime) })
3:postman发请求,查看处理结果:get方式,请求地址:http://127.0.0.1/user body中的响应就是, req.startTime
总结以后我们相同的操作, 可以定义到一个中间件中去处理

2.4: 定义多个全局中间件

// ------------------------- 定义多个全局中间件 -------------------------------
如何同时绑定多个中间件
中间件是可以同时注册多个的, 后续的每一个请求,会出触发这个中间件。
同时定义多个中间件代码示例:
1:注册多个中间件 app.use((req, res, next()) => { next( ) })
                      app.use((req, res, next()) => { next( ) })
2:发起请求 app.get('/user', (req, res) => { console.log('xx') })
3:postman测试:请求方式, GET, 请求地址:http://127.0.0.1/user, Body响应send中的信息
4:服务器【终端】的打印:打印了2个全局中间触发所打印的结果
总结:postman的Body中打印的是send中的信息【如果是浏览器发起的数据请求,则会在浏览器的页面上send展示响应结果。  终端【也可以称呼为服务器】的响应则是普通的console.log(). 】

2.5:局部生效的中间件

// ------------------------------------ 局部生效的中间件 -----------------------------------
局部中间件的使用方法
没有使用app.use创建的中间件就叫局部中间件, 他能当做请求的第二个参数去使用
具体使用方法:
1:定义局部中间件【没使用app.use的中间件,就是局部的】const mw = (req, res, next) => { next( ) }
2:发起请求,触发局部中间件:app.get('/', mw, (req, res) => { res.send('xx') } )
3:psotman接口测试 : 请求方式 GET, 请求接口: http://127.0.0.1, Body中响应send的返回内容
4:服务器响应: 服务器终端打印了, 中间件中的内容,表示触发了中间件
总结:没使用app.use注册的件, 就叫中间件。 他能当做请求的第二个参数被触发

2.6: 使用多个局部中间件

// ----------------------------- 使用多个局部中间件 -----------------------------
使用多个局部中间件, 是可以当第二个参数来用的, 
多个中间件, 用逗号隔开。或者多个中间件用[ ]用中括号包裹

2.7: 了解中间件的5个注意事项

//----------------------------- 了解中间件的5个注意事项 ----------------------------------
中间件的5个注意事项:
1: 一定要在路由之前注册中间件
2:客户端发送过来的请求是可以连续调用多个中间件进行处理
3: 执行完中间件的代码不要忘记调用next( )函数
4:为了防止代码逻辑混乱, 调用next( ) 函数后, 就不要在写额外的代码
5:连续调用多个中间件时, 多个中间件之间, 共享req, 和res对象

2.8: 了解什么是应用级别和路由级别的中间件

// ------------------------- 了解什么是应用级别和路由级别的中间件 -------------------------------
中间件的分:分为5大类
1:应用级别的中间件: app.use((req, res, next)=> {}), 挂载在app.use或者app.get、app.post
2:路由级别的中间件:绑定到express.Router身上const router = express.Router()  router.use(function(req, res, next) { next() })

2.9: 错误级别的中间件

// --------------------------- 错误处理中间件 -------------------------------
1: 在请求中,自定义一个错误信息: app.get('/', (req, res) => {throw new Error('服务器内部发生了错误')})
2:错误处理中间件, 就是多了一个err参数, 能接收到err.message错误消息: app.use((err, req, res, next) => { console.log('发生了错误!', err.message)   res.send('Error: ' + err.message )})  注意:console.log()是打印在服务器中, send是响应到body页面中

2.9.1: 了解3个内置的中间件

// ------------------- 了解3个内置的中间件 -----------------------
express内置中间件
express.static托管静态资源
express.json解析json请求体数据
express.urlencoded解析 URL-encoded 格式的请求体数据

2.9.2: 演示express.json中间件的使用

//------------------------  演示express.json中间件的使用 -----------------------------
express.json的使用【讲json对象,转换为真正的对象】
1: 调用json方法解析:app.use(express.json)
2:req.body打印的是经过转换的:app.post('/user', (req, res) => { console.log(req.body) })  转换前undefined, 转换后{name: 'zs', age: 20}
3:  postman测试接口: post方式,请求地址:http://127.0.0.1/user 
3.1:  Body/raw/JSON/ : {"name": "zs", "age": 20}
4: 服务器打印: 转换前undefined, 转换后{name: 'zs', age: 20}

2.9.3:express.urlencoded中间件的使用

//-------------------------- express.urlencoded中间件的使用 ----------------------------------
express.urlencoded解析x-www-form-urlencoded类型的数据
1: 全局挂载方法,解析数据:app.use(express.urlencode({extended: false})) 
2:postman发起数据请求: post-->http://127.0.0.1/book ---> Body/x-www-form-urlencode/ bookname: 水浒传, author: 施耐庵  
3:服务器端打印:转换前 { }空对象, 转换后: { bookname: '水浒传', author: '施耐庵' }

body-parser第三方中间件的使用

// ---------------------------- body-parser第三方中间件的使用 -------------------------------
旧方法: body.parser
1: 将下载的包映入, 在调用方法:const parser = require('body-parser') app.use(parser.urlencode({ extended: false }))
2:postman发起数据请求:post--》http://127.0.0.1/user-->body/ name: zs, age:22, gender: 男, 
3 :服务器打印:转换前undefined, 转换后{name: 'zs', age: 22, gender: '男'}
总结: express.urlencoded,就是基于他封装的

1: 自定义中间件

1.1: 介绍需求及实现步骤

初始化代码结构

1.2: 监听req的data事件

//--------------------- 监听req的data事件 -------------------------------
因为有可能客户端传输的数据过大, 要分批次传递过来, 会触发多个请求, 所以如果数据量大, 且无法一次传输完毕, 就是用data接受每次传输过来的一部分数据, 需要手动拼接数据, 形成一个完整的数据

1.3: 监听req的end事件

// --------------------------- 监听req的end事件 ----------------------------
请求完毕,调用res.end时间, 能拿到拼接的数据, 
1: res.end拿到数据:res.on('end', () => { console.log(str) })
2:app.post发起数据请求:app.post('/user', (req, res) => { res.send('ok') })

1.4: 使用querystring模块解析请求体数据

// ---------------------------- 使用querystring模块解析请求体数据 --------------------------------
调用系统内置模块,能够将字符串转换为真正的对象类型。
1: 导入内置模块: const es = reqiure('querystring')
2: 使用内置模块的.parse()方法将字符串转换为对象类型: const body = qs.parse(str)将字符串,转换为对象类型

1.5: 为req挂载自定义的body属性

//---------------------------  为req挂载自定义的body属性 --------------------------------
将转换的对象挂载到req.body身上, 
app.use((req, res, next) => {
   let str = '',
   req.on('data', (chunk) => {
     str += chunk
  })
  res.on('end', () => {
    const body = qs.parse(str)
    req.body = body
    next()
  })
})
1: 发起请求: app.post('/user', (req, res) =>{
   res.send('req.body')
})
2:postman接口测试: post--> http://127.0.0.1/user-->Body/ name: 'zs',age: 20, gender: 男, ---> Body / {"name" :"zs", "age": 20, "gender":"男"} 变成了json对象

1.6:将自定义中间件封装为独立的模块

将请求体数据转换为对象,然后挂载到req.body中, 单独封装成模块, 再导出去
接收抽离出去的模块, 将模块挂载在app.use成为一个全局处理中间件。
中间件处理流程: 
1: 创建服务器, 导入模块, 将模块注册为全局中间件,监听服务器。 发起数据请求,将数据打印到body中
2:调用querystring将字符串转换为真实大小, 在挂载到req.body上,打印查看, 将这个模块导出去

1:1基于express写接口

1.1 : 创建基本的服务器

1.2: 创建API路由模块

// ---------------------  创建API路由模块 ------------------------
在其他js文件中调用了express.Router创建了路由对象,并导出了
在自己的页面中,导入了这个文件, 并接收了它的router方法

1.3: 编写GET接口

// ------------------------------ 编写GET接口 -----------------------------
注意此时在路由js中挂载到router,get下的请求,需要在前面加上/api才能访问到数据。 
因为query=req.query接收到了请求地址的数据信息。 所以在页面响应的时候, data就是params中的信息。【注意请求地址:http://127.0.0.1/api/get】

1.4:编写POST接口

//--------------------- 编写POST接口 ------------------------
get请求的req.query是在params或者直接在请求地址后面携带参数, 而post是在body中x-www-urlencoded中写, 接收的也是req.body

post 请求是, 在引入的页面文件中需要先app.use(express.urlencoded(extend: false))才能解析表单中的数据

下一篇:后端-Node系列四:Mysql数据库