关于中间件广义上的中间件是指能够为操作系统以外的应用程序提供功能的软件,范围从云计算的各种服务厂商针对某个领域的小A检测模块。Express中间件特指基于Express中间件机制提供功能的软件模块。Express在3.x及更早版本中依赖Connect作为底层中间件机制。从4.x版本开始,内置了兼容Connect的中间件机制,因此Express中可以直接使用基于Connect的中间件。Express会以队列的形式组织处理过程。派发请求时,递归传递next方法依次调用处理过程(详见源码):写一个上一章完成的路由校正中间件项目licg9999/nodejs-server-examples-02-validatehas一个小问题,无法访问非标准路径的接口,比如无法访问http://localhost:9000/api//shop:现在使用中间件解决此类问题:$mkdirsrc/middlewares#新建src/middlewares存放自定义中间件的目录$tree-L2-Inode_modules#显示除node_modules以外的目录内容结构。├──Dockerfile├──package.json├──public│├──glue.js│├──index.css│├──index.html│└──index.js├──src│├──控制器│├──中间件│├──模具│├──服务器。js│└──服务└──yarn.lock//src/middlewares/urlnormalize.jsconst{normalize}=require('path');const{parse,format}=require('url');module.exports=functionurlnormalizeMiddleware(){return(req,res,next)=>{//解决在windows和linux系统中normalize路径分隔符使用不一致的问题constpathname=normalize(req.path).split('\\')。加入('/');consturlParsed=parse(req.url);让shouldRedirect=false;//重定向非标准路径if(req.path!=pathname){urlParsed.pathname=路径名;应该重定向=真;}//执行重定方向或策略过if(shouldRedirect){res.redirect(format(urlParsed));}else{下一个();}};};//src/middlewares/index.jsconst{Router}=require('express');consturlnormalizeMiddleware=require('./urlnormalize');module.exports=asyncfunctioninitMiddlewares(){constrouter=路由器();router.use(urlnormalizeMiddleware());返回路由器;};//src/server.jsconstexpress=require('express');const{resolve}=require('path');const{promisify}=require('util');+constinitMiddlewares=require('./middlewares');constinitControllers=require('./controllers');//...asyncfunctionbootstrap(){server.use(express.static(publicDir));server.use('/moulds',express.static(mouldsDir));+server.use(awaitinitMiddlewares());server.use(awaitinitControllers());awaitpromisify(server.listen.bind(server,port))();console.log(`>在端口${port上启动}`);}bootstrap();访问http://localhost:9000/api//shop可以看到自动重定向到有效路由:补充storeadditionlogic目前store管理缺少storeadditionlogic,因为post解析需要依赖在中间件body-parser上,所以本章添加了这个函数执行body-parser安装命令:$yarnaddbody-parser#...infoDirectdependencies└─body-parser@1.19.0#...后端处理://src/services/shop.js//...classShopService{//...+asynccreate({values}){+awaitdelay();++constid=String(+1++Object.keys(memoryStorage).reduce((m,id)=>Math.max(m,id),-Infinity)+);++返回{id,...(memoryStorage[id]=values)};+}}//...//src/controllers/shop.jsconst{Router}=require('express');+constbodyParser=require('body-parser');constshopService=require('../services/shop');const{createShopFormSchema}=require('../moulds/ShopForm');classShopController{shopService;asyncinit(){this.shopService=awaitshopService();常量路由器=路由器();router.get('/',this.getAll);router.get('/:shopId',this.getOne);router.put('/:shopId',this.put);router.delete('/:shopId',this.delete);+router.post('/',bodyParser.urlencoded({extended:false}),this.邮政);返回路由器;}//...+post=async(req,res)=>{+const{name}=req.body;++try{+awaitcreateShopFormSchema().validate({name});+}catch(e){+res.status(400).send({success:false,message:e.message});+return;+}++constshopInfo=awaitthis.shopService.create({values:{name}});++res.send({success:true,data:shopInfo});+};}//...前端处理://public/index.js//...exportasyncfunctionrefreshShopList(){constres=awaitfetch('/api/shop');const{data:shopList}=awaitres.json();consthtmlItems=shopList.map(({id,name})=>`
