对于node.js中的其他模块,后面慢慢梳理以下再记录,这两天脑阔都快装不下东西了,今天先记录一下express的学习吧。
1.安装和简单使用
首先新建一个文件夹:
执行npm init进行初始化,方便记录我们安装的包
执行npm iinstall express,稍等片刻安装成功后新建index.js试着搭建服务器,代码如下:
/*
* @Author:梅子黄时雨
* @Date: 2023-02-10 10:25:34
* @LastEditTime: 2023-02-10 11:40:54
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \nodeTest\node\express学习\index.js
*/
//导入,挂载
const express = require('express')
const app = express()
// 第一个参数是路径,支持字符串,字符串模式以及正则模式进行匹配
//第二个参数是个回调函数,具体的放到后续来写~
app.get("/", (req, res) => {
//req指的是前端的请求参数,res指的是我们要返回给前端的响应参数
// send()方法封装了之前的res.write()和res.end(),支持字符串/html模板/json并返回给前端
// res.send(`
// <html>
// <h1>Hello world</h1>
// </html>
// `)
res.send({
name: 'libai'
})
})
//支持的路径模式如下:
//表示匹配/abd或者/abcd的路径
app.get("/ab?cd", (req, res) => {
res.send("login")
})
// 表示符合/ab/内容格式的路径
app.get("/ab/:id", (req, res) => {
res.send("login")
})
// 表示复合在ab和cd之间添加n个字符串的字符
app.get("/ab*cd", (req, res) => {
res.send("login")
})
// 表示当前字符重复n次的路由
app.get("/ab+cd", (req, res) => {
res.send("login")
})
// 表示当前字可选的路由 cd可都写也可都不写
app.get("/ab(cd)?ef", (req, res) => {
res.send("login")
})
// 正则表达式匹配
app.get("/.*fly$/", (req, res) => {
res.send("fly")
})
app.listen(10086, () => {
console.log("server start")
})
现在启动服务器,输入以上路径就可以访问对应的页面了(感慨一下:express的路径真的很灵活)
2.中间件
我们将上文提到的回调函数称为中间件。中间件其实指的就是一个函数,可以访问请求对象,响应对象和web应用中处于请求-响应循环流程的中间件,一般被命名为next的变量。如果当前中间件没有终结请求响应循环,则必须调用next方法将控制权交给下一个中间件,否则请求就会挂起。它的功能如下:
-
执行任何代码
-
修改请求和相应对象
-
终结请求-响应循环
-
调用堆栈中的下一个中间件
先写个简单的实例来理解一下中间件: 作为一个后端人员,在前端进行操作并且传递参数给后端时,这个时候的处理一般分为三步:
- 拿到前端给的参数先去验证它的token是否过期,
- 要去查询数据库
- 读取数据做处理返回给前端。
假设前端需要的数据很多,你需要查好几个表,然后经过一系列复杂的处理才能拼接好,一方面这个时候如果所有的代码都写在一个函数里,那么这个函数体将十分臃肿,另一方面就是这个过程是循序渐进的,先做第一步,再去进行第二步,第三部。这个时候就体现了中间件的作用:先验证token是否通过,如果不通过直接res.send(‘error’),如果通过,那就next()放行去执行下一个中间件,直至有res.send()返回数据和响应给前端。而三个步骤可以封装成三个函数,用法也十分灵活,各位看官请看下图:
/*
* @Author:梅子黄时雨
* @Date: 2023-02-10 10:25:34
* @LastEditTime: 2023-02-10 13:54:28
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \nodeTest\node\express学习\index.js
*/
const express = require('express')
const app = express()
const func1 = (req, res, next) => {
// 验证token
// 查询数据库
// 返回内容
console.log('验证token')
// 在函数中要不然用send退出,要不然用next放行
// 中间件互相通信,在next之前,利用res加属性挂值
res.name = "李白"
next()
}
const func2 = (req, res, next) => {
res.send({
list: [1, 2, 3, 4, 5],
name: res.name
})
}
app.get('/home',[func1,func2])
app.get("/list", [func1],(req, res) => {
res.send({
name: "hanxin"
})
})
app.listen(10086, () => {
console.log("server start")
})
中间件的作用就体现出来啦,并且他可以自行配置。这说明个数是我们自定义的,即可以按照需求和降低代码耦合度的原则来配置中间件。
在express中,中间件大概分为如下几种:
-
应用级中间件
-
路由级中间件
-
错误处理中间件
-
内置中间件
-
第三方中间件
先写一下应用级中间件和路由中间件吧。
应用级中间件
应用级中间件:类似于vue的导航守卫,用法:app.use(fcuntion),但是要注意使用的位置, 一旦挂在app上,所有的应用都会去使用的,如果说写了一个拦截error的,挂载在了所有的中间件之前,那永远看到的就都是处理错误的页面喽~~话不多说,上代码:
/*
* @Author:梅子黄时雨
* @Date: 2023-02-10 10:25:34
* @LastEditTime: 2023-02-10 13:54:28
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \nodeTest\node\express学习\index.js
*/
const express = require('express')
const app = express()
app.get("/", (req, res) => {
res.send({
name: 'libai'
})
})
// 默认路径/放在use方法之前,所以不会去执行以下定义的中间件
// next():执行完当前函数继续执行下一个函数
const func1 = (req, res, next) => {
//验证token,cookie是否过期
// 查询数据库
// 返回内容
console.log('验证tooken')
// 中间件互相通信,在next之前,利用res加属性挂值
res.name = "李白"
next()
}
app.use(func1) //挂载func1,以下出现的路径都首先要去执行func1
const func2 = (req, res, next) => {
res.send({
list: [1, 2, 3, 4, 5],
name: res.name
})
}
app.get("/home", [func2])
app.get("/list", (req, res) => {
res.send({
name: "hanxin"
})
})
app.listen(10086, () => {
console.log("server start")
})
重启服务器,就会发现除了http://localhost:10086这个路径控制台不会出现验证tooken,访问后面的路径都会去执行func1
方便时方便,但是一定要注意挂载的位置啊。
路由级中间件
路由级中间件自然是用来处理路由的啦,比起前文配置一个路由如此麻烦,express提供的路由中间件以及获取参数的方法真的是很简便了。来看下具体用法吧,我们将所有的路由按照目录分好建立相应的文件夹,并设置入口index文件:
/*
* @Author:梅子黄时雨
* @Date: 2023-02-10 13:57:07
* @LastEditTime: 2023-02-10 17:29:13
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \nodeTest\node\express学习\路由中间件.js
*/
//入口文件
const express = require('express')
const app = express()
const HomeRouter = require('./homerouter.js')
const LoginRouter = require('./loginRouter')
function application(req, res, next) {
console.log("应用中间件,验证tooken")
next()
}
app.use(application)
// 应用级别,有顺序的
// 配置post参数的中间件
app.use(express.urlencoded({
extended: false }))//解析前端参数格式
app.use(express.json()) //解析前端参数格式
app.use("/home", HomeRouter)//控制一级匹配 匹配到/home目录下的路由
app.use("/login", LoginRouter)//控制一级匹配 匹配到/login目录下的路由
app.use((req, res) => {
res.status(404).send('丢了')//调用send,返回的状态码一定是200,用status可以返回其他的
})//控制一级匹配 匹配到ogin目录下的路由
app.listen(10086, () => {
console.log("server start")
})
新建HomeRouter,LoginRouter来存放与各自功能相应的功能,在入口文件引入进行匹配,我们着重看一下如何获取到前端传递的参数,用到一个小工具postaman,我们记录一下利用login来实现传参和获取参数的功能
/*
* @Author: 梅子黄时雨
* @Date: 2023-02-10 13:57:07
* @LastEditTime: 2023-02-10 17:33:45
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \nodeTest\node\express学习\路由中间件.js
*/
const express = require('express')
const router = express.Router()
// 路由级别中间件,响应前端的get请求
router.get('/', (req, res) => {
console.log(req.query) //获取get请求参数
res.send('login-success')
})
// 路由级别中间件,响应前端的post请求
router.post('/', (req, res) => {
console.log('req>>', req) //获取post请求参数,必须配置中间件
res.send({
ok: 4 })
})
module.exports = router
重启服务器,我们测试一下结果: