当前位置: 首页 > Web前端 > JavaScript

node.js-路由,中间件,mysql

时间:2023-03-27 11:45:02 JavaScript

这几天好晚,今天看的内容不多,不知道为什么学了这么晚。今天的内容还是有点多,有点自相矛盾,再说一遍。1、今天首先来了解一下路由的概念。什么是路由?路由就是映射关系。在express中,路由指的是客户端请求与服务端处理功能之间的映射关系。路由由三部分组成:请求类型、请求url、处理函数。app.get(url,callback)其实和我们前面说的监听事件是一样的。constexpress=require('express')constapp=express()app.get('/',(req,res)=>{res.send('getrequestreceived')})app.listen(80,()=>console.log('expressserverrunningathttp://127.0.0.1'))这是最简单的路由。路由匹配过程,每次请求到达服务器,都需要先进行路由匹配,只有请求类型和url匹配成功后才会调用后续的请求函数。,用法最简单的用法就是像我们上面那样直接挂在实例上,不推荐,因为一个请求一个挂一个,既麻烦又麻烦。科学的做法应该是创建一个路由模块。分为五个步骤:创建路由js文件、调用express.Router创建路由对象、挂载路由、导出路由对象。最后,我们的入口文件需要通过app.use导入注册//1.导入expressconstexpress=require('express')//2.创建路由对象constrouter=express.Router()//3.挂载路由//3.1挂载路由获取用户信息router.get('/user/:id',(req,res)=>{res.send(req.params)})//3.2挂载路由到接受用户发送的请求router.post('/post',(req,res)=>{res.send('postsuccess')})//4.向外共享路由成员module.exports={express,router}constexpress=require('./02modularrouting')constapp=express.express()//注册路由app.use(express.router)app.listen(80,()=>console.log('expressserver运行在http://127.0.0.1'))昨天说说app.use可以看到,其实是用来注册全局中间件的。然后我们也可以给路由挂载一个前缀,通过app.use添加的方法和昨天基本一样。2、中间件是指业务流程的中间处理环节。即当客户端请求到达服务端时,可以不断调用多个中间件对请求进行预处理,最后通过路由发送出去。中间件的本质就是一个函数有一个类似但多了一个参数,下一个参数。next是一个函数,它的作用是实现多个中间件连续调用的key,并将传递关系传递给下一个中间件或者路由,每个中间件都有下一个传递给路由,然后响应客户就结束了.2.1我们首先看到全局生效的中间件,也就是说客户发起的任何请求都会被触发,直接通过app注册即可。useconstexpress=require('express')constapp=express()//middleItemconstmw=function(req,res,next){//res.send('Thisisthemiddlewarelink')console.log('Thisisthemiddlewarelink')next()}//viaapp.use被定义为全局有效的中间件app.use(mw)app.get('/user',(req,res)=>{res.send('Thisisagetrequest')})app.post('/post',(res,req)=>{res.send('这是一个post请求')})app.listen(80,()=>{console.log('http://127.0.0.1');})中间件的作用:多个中间件共享同一个res和req,所以这些对象可以定义在上游中间件中,下游可以直接使用包括路由。如何定义多个全局中间件,直接通过app.use可以定义多个。就像昨天说的静态资源的托管,如果有多个目录,就多注册一个。2.2部分中间件没有使用app.use,只对部分路由有效,路由的参数规则也发生了变化。constexpress=require('express')constapp=express()constmw=function(req,res,next){req.time=Date.now()next()}app.get('/',mw,(req,res)=>{res.send('部分有效'+req.time)})app.get('/user',(req,res)=>res.send('无效')+req.time)app.listen(80,()=>{console.log('http://127.0.0.1');})定义多个本地中间件并编写多个函数,参数可以用逗号分隔,你也可以直接写数组。有个注意:路由前一定要先注册中间件,不然路由执行完谁来执行中间件。2.3中间件的分类①应用级中间件是通过get、post、use绑定到app的中间件②路由级中间件是刚才穿插在我们路由模块中的中间件③错误级中间件这个有个说法是专门用的捕获错误信息和形式参数已更改为四个。他也是卸载路由背后唯一的中间件。constexpress=require('express')const{rename}=require('fs')constapp=express()app.get('/',(req,res)=>{//1.人为抛出错误,一旦有错误,后续的响应将不会被执行thrownewError('服务器内部发生错误')res.send('我无法执行')})//2.错误中间件app.use((err,req,res,next)=>{//2.1向服务器打印错误console.log(err.message);//2.2向客户端发送错误res.send(err.message)//这样做的好处是,如果早一点出错,整个服务器都崩溃了,什么都执行不了,这样,就可以正常输出错误信息,正常执行下面的代码})app.listen(80,()=>console.log('expressserverrunningathttp://127.0.0.1'))④内置中间件三内置的中间件是express.static,前面已经说过了。express.json用于解析json格式的数据。express.urlencoded用于解析urlencoded格式的数据。后两者通常配合req.body获取请求体。然后把数据拿来给他们分析constexpress=require('express')constapp=express()//注意这里是中间件所以必须在路由之前配置app.use(express.json())app.use(express.urlencoded({extended:false}))app.post('/',(req,res)=>{//通过req.body可以获取请求body数据//postman在测试的时候在body中选择raw然后选择text为json发送json数据console.log(req.body);//解析前json数据未定义})//测试urlencoded数据体//该数据体格式为x-www-form-urlencoded//固定写法app.post('/user',(req,res)=>{//没有预解析的时空对象console.log(req.body);})app.listen(80,()=>console.log('expressserverrunningathttp://127.0.0.1'))⑤第三方中间件通过npm注册app.use直接安装导入使用2.4自定义中间件这里是自定义一个类似于express.urlencoded函数解析请求体数据的中间件的案例constexpress=require('express')constapp=express()//4.使用node内置模块解析请求体数据。node中内置了一个查询字符串模块,专门用于处理查询字符串。//该模块提供的parse()函数可以将查询字符串转换为对象constqs=require('querystring')//1.定义中间件app.use((req,res,next)=>{//2.监听数据事件,因为既然是服务端,肯定会收到蹩脚的客户端,如果有时候请求量太大,会分批向服务端发送数据,所以数据事件可能会触发多次times//需要将每条数据拼接在一起letstr=''req.on('data',chunk=>{str+=chunk})//3.req的结束事件会在请求体是时自动触发接收到完整的请求体数据,这里可以处理结束事件req.on('end',()=>{console.log(str);str=qs.parse(str)console.log(str);//5.说明洗过的对象给到req.bodyreq.body=strnext()})})app.post('/',(req,res)=>{res.send(req.body)})app.listen(80,()=>console.log('http://127.0.0.1'))然后将自定义中间件模块化//4.使用node内置模块解析请求体数据,node中内置了一个querystring模块,专门用来处理查询字符串。//本模块提供的parse()函数可以将querystrings转换成对象constqs=require('querystring')//因为是别人导入的,直接注册使用,所以可以把constbodyParse保存在app中.use通过省略一些冗余代码,例如应用程序打开服务器。bodyParse=(req,res,next)=>{//2.监听数据事件,因为既然是服务端,那么肯定会收到来子客户端的请求。如果有时候请求量太大,会分批向服务器发送数据,所以可能会多次触发数据事件。//每次都需要拼接数据letstr=''req.on('data',chunk=>{str+=chunk})//3.req的结束事件会在请求体是时自动触发已收到。结束事件可以在这里处理完整的请求体数据req.on('end',()=>{console.log(str);str=qs.parse(str)console.log(str);//5.向req.body解释洗过的对象req.body=strnext()})}module.exports=bodyParseconstbodyParse=require('./custommiddlewaremodular')constexpress=require('express')constapp=express()app.use(bodyParse)app.post('/',(req,res)=>{//res.send('getrequestreceived')console.log(req.body);})app.listen(80,()=>console.log('expressserverrunningathttp://127.0.0.1'))3、我们继续看到使用express写接口分为三个步骤:创建一个基础服务器,创建一个api路由模块,编写一个获取界面。ThisisroutingModule//2.写api路由模块是为了模块化路由,因为需要注册使用和挂载api前缀constexpress=require('express')constrouter=express.Router()//3.写get接口router.get('/get',(req,res)=>{//3.1首先获取用户发送的数据letdata=req.query//3.2将数据发送给客户端res.send({status:0,//0表示成功,1表示失败msg:'getrequestsucceeded',data:data//返回数据给客户端})})//4.编写post接口router。post('/post',(req,res)=>{//4.1客户端发送的数据letdata=req.bodyres.send({status:0,msg:'post请求成功',data:data})})module.exports=router其实主要是通过req的属性获取数据,然后通过send方法发送给客户端。下面是入口文件,主要是启动服务器,然后分析数据//1.创建一个基本的web服务器constexpress=require('express')constapp=express()//2.1导入路由模块并挂载前缀constrouter=require('./router')//4.2注册内置中间件或req.body无法解析)app.use('/api',router)app.listen(80,()=>{console.log('http://127.0.0.1');})有些东西需要稍后阅读才能知道我刚刚提到了4.cors和jsonp。我们刚才的案例其实有一个bug,就是有跨域的问题。我们创建一个html文件,通过一个按钮获取数据。这时,由于协议不同,会受到同源策略的约束。组织。我们之前也说过,一个是cors,一个是jsonp,解决跨域。我们这里一定不能用jsonp,因为它只支持get,那怎么用cors呢?直接安装导入注册三部曲解决跨域问题,就这么简单。4.1什么是cors?它由一系列http响应标头组成。当同源策略遇到这个header时,就会解除限制。cors一般配置在服务端,客户端不需要。下面是一些理解内容响应头:第一个res.setHeader('Access-Control-Allow-Orign','http:wwwssss.smart,')表示只允许本网站后面的域名访问,如果是的话是*,表示允许任何域访问。二是在之前基础上的Allow-Headers。我们的cors默认值只有9个请求标头。如果超过这九个header,请求必然失败。这九个之外的第三个可以通过这段代码添加。在第三个的基础上——Methodscors默认只支持getposthead。其他的需要用这个来设置。4.2现在不是理解内容了。cors请求的分类大致分为简单请求和preflight请求。什么是满足两个条件的简单请求:一是请求方法在默认的三个以内,二是HTTP请求头不能超过默认的九个什么是预检请求?三个条件之一满足,一个是请求头。九种之外,一种是请求方式在这三种之外,一种是发送的数据是json数据。那么它们之间有什么区别呢?这很简单。简单请求只会发送一次请求,而预检请求会发送两次请求,为什么呢?因为pre-checkrequest会在server和client连接之前提前发送一个optionrequest作为pre-check,看server是否可以连接这种格式的request。只有请求成功才会开始正式请求,携带真实的数据。5、今天最后一个内容是jsonp接口。首先,如果说已经配置了cors,在配置cors之前一定要先声明jsonp接口,否则会混淆。在制作这个接口之前,先来应对一下jsonp的知识。首先是解决跨域。我们通过script标签传入函数,然后调用接口。这个方法叫做jsonp//1.创建一个基本的webserverconstexpress=require('express')constapp=express()//2.1导入路由模块并挂载前缀constrouter=require('./router')//4.2注册内置中间件否则req.body将无法解析app.use(express.urlencoded({extended:false}))//6.jsonp接口必须写在coesapp.get之前('/api/jsonp',(req,res)=>{//6.1getcallbackfunctionThenameofletfn=req.query.callback//6.2定义要传回的数据对象letdata={name:'张三',age:15}//6.3模拟函数调用letfnDiao=`${fn}(${JSON.stringify(data)})`//6.4数据返回res.send(fnDiao)})//5.cors解决跨域constcors=require('cors')const{json}=require('body-parser')app.use(cors())app.use('/api',router)app.listen(80,()=>{console.log('http://127.0.0.1');})