内容:Express框架开发 日期:xx-xx
一、中间件
1.1 简介
中间件(Middleware),特指业务流程的中间处理环节。我们可以把中间件比作工厂中的车间。比如:在处理铁矿石的时候,一般都要经过三个处理环节,从而保证处理过后的矿石达到标准的钢材。处理铁矿石的这三个中间处理环节,就可以叫做中间件。而中间件其实是路由的升级,也能达到请求的匹配,只不过必须要进行下一步处理,以到达最终的路由匹配,就像在工厂中生产产品,最后必须要出厂。
1.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端口'); }); // let obj = {}; // obj.x = 99; //自定义中间件 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.use(getTimes); //老师界面 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.use(getTimes); //老师界面 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 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()【重点】
参考手册地址: 利用 Express 托管静态文件 - Express 中文文档 | Express 中文网
参考手册地址: 利用 Express 托管静态文件 - Express 中文文档 | Express 中文网
什么是开放静态资源?
就是让用户通过服务端来访问我们的静态资源(比如:.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); });