一、中间件
1.1 简介
中间件(Middleware),特指业务流程的中间处理环节。我们可以把中间件比作工厂中的车间。比如:在处理铁矿石的时候,一般都要经过三个处理环节,从而保证处理过后的矿石达到标准的钢材。处理铁矿石的这三个中间处理环节,就可以叫做中间件。而中间件其实是路由的升级,也能达到请求的匹配,只不过必须要进行下一步处理,以到达最终的路由匹配,就像在工厂中生产产品,最后必须要出厂。
1.2 中间件的好处
1.2.1、使用中间件可以拆分我们的业务,使业务流程更清晰。
1.2.2、后期维护更加方便。
1.3 中间件执行流程
什么是中间件?【重点】
当一个请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理。但是必须要有一个最终的匹配路由进行响应给客户端结果。
1.4 使用中间件
1.4.1 使用中间件的语法
app.use( [前缀,]中间件函数 )
callback( req,res,next )
//在模块化路由文件中使用自定义的中间件:
router.use(中间件函数)
使用中间件要注意的事项:【重点】
1)、在自定义的中间件函数内部要手动调用next()方法,next()方法会执行后续操作;
2)、使用中间件的代码通常放在所有路由的最前面,但404错误中间件通常放在所有路由的最后面;
3)、如果中间件中的业务出现异常时通常会把异常信息当作next()方法的参数,如果没有定义使用逻辑错误处理中间件(含有err,req,res,next四个形参的中间件),则next()会把这些异常信息直接输出界面上,如果定义并使用了逻辑错误处理中间件则next()方法会自动查找并执行这个逻辑错误处理中间件;
1.4.2 基本使用
const express = require('express');
const timestamp = require('time-stamp');
const app = express();
app.listen(4000, () => {
console.log('4000端口');
});
//自定义中间件
function getTimes(req, res, next) {
//获取当前日期时间并放在req对象上
req.curtime = timestamp('YYYY-MM-DD HH:mm:ss');
next(); //next()方法:查找并执行后面能匹配上的路由
}
//使用中间件:(必须在界面前使用)
app.use(getTimes);
//学生界面
app.get('/student', (req, res) => {
res.send(`学生界面: ${req.curtime}`);
});
//老师界面
app.get('/teacher', (req, res) => {
res.send(`老师界面: ${req.curtime}`);
});
1.4.3 中间件加前缀
在使用自定义中间件时加前缀,则只对某个路由才使用这个自定义的中间件,代码如下:
const express = require('express');
const timestamp = require('time-stamp');
const path = require('path');
const app = express();
app.listen(4000, () => {
console.log('4000端口');
});
//自定义中间件
function getTimes(req, res, next) {
//获取当前日期时间并放在req对象上
req.curtime = timestamp('YYYY-MM-DD HH:mm:ss');
if (1) { //正确
// if (0) { //错误
next();
} else { //错误
next('这里错误信息...');
}
}
//使用中间件:
app.use(getTimes);
app.use('/teacher', getTimes);
//学生界面
app.get('/student', (req, res) => {
res.send(`学生界面: ${req.curtime}`);
});
//老师界面
app.get('/teacher', (req, res) => {
res.send(`老师界面: ${req.curtime}`);
});
1.5 中间件种类
1.5.1 应用级别的中间件
const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('web服务器工作在3000端口');
});
const indexRouter = require('./index.js');
app.use(indexRouter);
index.js路由模块文件代码如下:
const express = require('express');
const router = express.Router();
//设计路由:
//首页轮播图:
router.get('/banners', (req, res) => {
res.send('轮播图');
});
//首页同步课程:
router.get('/syncourse', (req, res) => {
res.send('同步课程');
});
//首页精品课程:
router.post('/jpincourse', (req, res) => {
res.send('精品课程');
});
//暴露router 一定记得暴露router
module.exports = router;
1.5.2 错误中间件
1.5.2.1 404错误中间件:
const express = require('express');
const timestamp = require('time-stamp');
const path = require('path');
const app = express();
app.listen(4000, () => {
console.log('4000端口');
});
//自定义中间件
function getTimes(req, res, next) {
//获取当前日期时间并放在req对象上
req.curtime = timestamp('YYYY-MM-DD HH:mm:ss');
if (1) { //正确
// if (0) { //错误
next();
} else { //错误
next('这里错误信息...');
}
}
//使用中间件:
app.use(getTimes);
//学生界面
app.get('/student', (req, res) => {
res.send(`学生界面: ${req.curtime}`);
});
//老师界面
app.get('/teacher', (req, res) => {
res.send(`老师界面: ${req.curtime}`);
});
//404错误处理中间件:
// app.use(function(req, res, next) {
// res.send(`404错误!`);
// });
function err404(req, res, next) {
//res.send(`这是404错误!!`);
res.sendFile(path.join(__dirname, '404.html'));
}
app.use(err404);
//自定义中间件:逻辑错误处理中间件
function proError(err, req, res, next) {
console.log(err, 8888);
//将错误信息写入错误日志文件中:
// fs.writeFileSync('system.log',err);
res.send(err);
}
app.use(proError);
1.5.2.2 逻辑错误中间件:
const express = require('express');
const timestamp = require('time-stamp');
const app = express();
app.listen(4000, () => {
console.log('4000端口');
});
//自定义中间件
function getTimes(req, res, next) {
//获取当前日期时间并放在req对象上
req.curtime = timestamp('YYYY-MM-DD HH:mm:ss');
// if (1) { //正确
if (0) { //错误
next();
} else { //错误
next('这里错误信息...');
}
}
//使用中间件:
app.use(getTimes);
//学生界面
app.get('/student', (req, res) => {
res.send(`学生界面: ${req.curtime}`);
});
//使用中间件:
// app.use(getTimes);
//老师界面
app.get('/teacher', (req, res) => {
res.send(`老师界面: ${req.curtime}`);
});
//自定义中间件:逻辑错误处理中间件
function proError(err, req, res, next) {
console.log(err, 8888);
//将错误信息写入错误日志文件中:
// fs.writeFileSync('system.log',err);
res.send(err);
}
app.use(proError);
1.5.3 内置中间件
1.5.3.1 开放静态资源:express.static()【重点】
就是让用户通过服务端来访问我们的静态资源(比如:.js文件、.css文件、图片文件、html文件)。
注意:将某个目录开放之后在访问时不需要带上该目录
入口文件的代码如下:
const express = require('express');
const timestamp = require('time-stamp');
const path = require('path');
const app = express();
app.listen(5000, () => {
console.log('5000端口');
});
//使用内置中间件express.static()来开放静态资源
//注意:将某个目录开放之后在访问时不需要带上该目录
// app.use(express.static(path.join(__dirname, 'html/image')));
// app.use('/image', express.static(path.join(__dirname, 'html/image')));
// app.use('/js', express.static(path.join(__dirname, 'html/js')));
// app.use('/css', express.static(path.join(__dirname, 'html/css')));
app.use(express.static(path.join(__dirname, 'public')));
//引入自定义的模块化路由文件:
let userRouter = require('./user.js');
app.use(userRouter);
user.js路由模块文件代码如下:
const express = require('express');
const router = express.Router();
const path = require('path');
const fs = require('fs');
//设计路由
//显示登录界面:
router.get('/login', (req, res) => {
res.sendFile(path.join(__dirname, 'login.html'));
});
// router.get('/image/banner3.png', (req, res) => {
// let content = fs.readFileSync(path.join(__dirname, 'html/image/banner3.png'));
// res.send(content);
// });
module.exports = router;
login.html文件代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/common.js"></script>
</head>
<body>
<div><img src="./image/banner3.png" alt=""></div>
<!-- <div><img src="./banner3.png" alt=""></div> -->
<div>帐号:<input type="text" name="user"></div>
<div>密码:<input type="password" name="pwd"></div>
<div><input type="submit" value="登录"></div>
</body>
</html>
1.5.3.2 接收post参数【重点】
使用内置中间件express.urlencoded()来接收post方式的键值对格式发送的参数:
参考手册地址: Express 4.x - API Reference - Express 中文文档 | Express 中文网
app.use(express.urlencoded({extended:false}))
使用内置中间件express.json()来接收psot方式的json格式发送的参数:
app.use(express.json())
通过vscode插件rest client来模拟发送post方式的请求并传参:【重点】
api.http文件参考如下:
@url=http://localhost:5000
get {{url}}/city?cid=111&usr=lisi HTTP/1.1
###
POST {{url}}/denglu HTTP/1.1
Content-Type: application/x-www-form-urlencoded
user=zhangsan&age=20&email=zs@qq.com
###
POST {{url}}/myjson HTTP/1.1
Content-Type: application/json
{"xingming":"李四","tel":110,"age":20}
1.5.4 第三方中间件
1.5.4.1 小图标
serve-favicon:这个第三方中间件用来动态生成网站小图标(favicon.ico)
1.5.4.2 图片验证码
svg-captcha
//引入express
const express = require('express');
const fs = require('fs');
const path = require('path');
const svgcaptcha = require('svg-captcha');
// console.log(express);
//创建应用
const app = express();
// console.log(app);
//监听端口:app.listen()
app.listen(3000, () => {
console.log('服务运行在3000端口');
});
//生成图片验证码:
app.get('/getcode', (req, res) => {
let svg = svgcaptcha.create({
width: 100,
height: 80,
background: '#cc9966',
size: 6,
ignoreChars: '0o1i',
noise: 3,
color: true
});
console.log(svg);
res.send(svg.data);
});