2023-03-28
一、koa2 快速开始
1、环境准备
因为node.js v7.6.0开始完全支持async/await,不需要加flag,所以node.js环境都要7.6.0以上 node.js环境 版本v7.6以上 npm 版本3.x以上
2、快速开始
2.1 安装koa2
# 初始化package.jsonnpm init# 安装koa2 npm install koa
2.2 hello world 代码
constKoa=require('koa')constapp=newKoa()app.use(async(ctx)=>{ctx.body='hello koa2'})app.listen(3000)console.log('[demo] start-quick is starting at port 3000')
2.3 启动demo
由于koa2是基于async/await操作中间件,目前node.js 7.x的harmony模式下才能使用,所以启动的时的脚本如下:
node index.js
二、async/await使用
1、快速上手理解
先复制以下这段代码,在粘贴在chrome的控制台console中,按回车键执行
functiongetSyncTime(){returnnewPromise((resolve,reject)=>{try{letstartTime=newDate().getTime()setTimeout(()=>{letendTime=newDate().getTime()letdata=endTime-startTimeresolve(data)},500)}catch(err){reject(err)}})}asyncfunctiongetSyncData(){lettime=awaitgetSyncTime()letdata=`endTime - startTime = ${time}`returndata}asyncfunctiongetData(){letdata=awaitgetSyncData()console.log(data)}getData()
2、从上述例子可以看出 async/await 的特点:
可以让异步逻辑用同步写法实现
最底层的await返回需要是Promise对象
可以通过多层 async function 的同步写法代替传统的callback嵌套
三、koa2简析结构
1、源码文件
├── lib │ ├── application.js │ ├── context.js │ ├── request.js │ └── response.js └── package.json
这个就是 GitHubhttps://github.com/koajs/koa上开源的koa2源码的源文件结构,核心代码就是lib目录下的四个文件
application.js 是整个koa2 的入口文件,封装了context,request,response,以及最核心的中间件处理流程。
context.js 处理应用上下文,里面直接封装部分request.js和response.js的方法
request.js 处理http请求
response.js 处理http响应
2、koa2特性
只提供封装好http上下文、请求、响应,以及基于async/await的中间件容器。
利用ES7的async/await的来处理传统回调嵌套问题和代替koa@1的generator,但是需要在node.js 7.x的harmony模式下才能支持async/await。
中间件只支持 async/await 封装的,如果要使用koa@1基于generator中间件,需要通过中间件koa-convert封装一下才能使用。
四、koa中间件开发和使用
koa v1和v2中使用到的中间件的开发和使用
generator 中间件开发在koa v1和v2中使用
async await 中间件开发和只能在koa v2中使用
1、generator中间件开发
1.1 generator中间件开发
generator中间件返回的应该是function * () 函数
/* ./middleware/logger-generator.js */functionlog(ctx){console.log(ctx.method,ctx.header.host+ctx.url)}module.exports=function(){returnfunction*(next){// 执行中间件的操作log(this)if(next){yieldnext}}}
1.2 generator中间件在koa@1中的使用
generator 中间件在koa v1中可以直接use使用
constkoa=require('koa')// koa v1constloggerGenerator=require('./middleware/logger-generator')constapp=koa()app.use(loggerGenerator())app.use(function*(){this.body='hello world!'})app.listen(3000)console.log('the server is starting at port 3000')
1.3 generator中间件在koa@2中的使用
generator 中间件在koa v2中需要用koa-convert封装一下才能使用
constKoa=require('koa')// koa v2constconvert=require('koa-convert')constloggerGenerator=require('./middleware/logger-generator')constapp=newKoa()app.use(convert(loggerGenerator()))app.use((ctx)=>{ctx.body='hello world!'})app.listen(3000)console.log('the server is starting at port 3000')
2、async中间件开发
2.1 async 中间件开发
/* ./middleware/logger-async.js */functionlog(ctx){console.log(ctx.method,ctx.header.host+ctx.url)}module.exports=function(){returnasyncfunction(ctx,next){log(ctx);awaitnext()}}
2.2 async 中间件在koa@2中使用
async 中间件只能在 koa v2中使用
constKoa=require('koa')// koa v2constloggerAsync=require('./middleware/logger-async')constapp=newKoa()app.use(loggerAsync())app.use((ctx)=>{ctx.body='hello world!'})app.listen(3000)console.log('the server is starting at port 3000')
Ⅱ、路由
一、koa2 原生路由实现
1、简单例子
constKoa=require('koa')constapp=newKoa()app.use(async(ctx)=>{leturl=ctx.request.url ctx.body=url})app.listen(3000)
访问http://localhost:3000/hello/world页面会输出 /hello/world,也就是说上下文的请求request对象中url之就是当前访问的路径名称,可以根据ctx.request.url 通过一定的判断或者正则匹配就可以定制出所需要的路由。
2、定制化的路由
demo源码
https://github.com/ChenShenhai/koa2-note/tree/master/demo/route-simple
2.1 源码文件目录
.├── index.js├── package.json└── view ├── 404.html ├── index.html └── todo.html
2.2 demo源码
constKoa=require('koa')constfs=require('fs')constapp=newKoa()/**
* 用Promise封装异步读取文件方法
* @param {string} page html文件名称
* @return {promise}
*/functionrender(page){returnnewPromise((resolve,reject)=>{letviewUrl=`./view/${page}`fs.readFile(viewUrl,"binary",(err,data)=>{if(err){reject(err)}else{resolve(data)}})})}/**
* 根据URL获取HTML内容
* @param {string} url koa2上下文的url,ctx.url
* @return {string} 获取HTML文件内容
*/asyncfunctionroute(url){letview='404.html'switch(url){case'/':view='index.html'breakcase'/index':view='index.html'breakcase'/todo':view='todo.html'breakcase'/404':view='404.html'breakdefault:break}lethtml=awaitrender(view)returnhtml}app.use(async(ctx)=>{leturl=ctx.request.urllethtml=awaitroute(url)ctx.body=html})app.listen(3000)console.log('[demo] route-simple is starting at port 3000')
2.3 运行demo
执行运行脚本
node -harmony index.js
二、koa-router中间件
如果依靠ctx.request.url去手动处理路由,将会写很多处理代码,这时候就需要对应的路由的中间件对路由进行控制,这里介绍一个比较好用的路由中间件koa-router
1、安装koa-router中间件
# koa2 对应的版本是 7.xnpm install --save koa-router@7
2、快速使用koa-router
constKoa=require('koa')constfs=require('fs')constapp=newKoa()constRouter=require('koa-router')lethome=newRouter()// 子路由1home.get('/',async(ctx)=>{lethtml=` <ul>
<li><a href="/page/helloworld">/page/helloworld</a></li>
<li><a href="/page/404">/page/404</a></li>
</ul>
`ctx.body=html})// 子路由2letpage=newRouter()page.get('/404',async(ctx)=>{ctx.body='404 page!'}).get('/helloworld',async(ctx)=>{ctx.body='helloworld page!'})// 装载所有子路由letrouter=newRouter()router.use('/',home.routes(),home.allowedMethods())router.use('/page',page.routes(),page.allowedMethods())// 加载路由中间件app.use(router.routes()).use(router.allowedMethods())app.listen(3000,()=>{console.log('[demo] route-use-middleware is starting at port 3000')})
Ⅲ、请求数据获取
一、GET请求数据获取
1、使用方法
在koa中,获取GET请求数据源头是koa中request对象中的query方法或querystring方法,query返回是格式化好的参数对象,querystring返回的是请求字符串,由于ctx对request的API有直接引用的方式,所以获取GET请求数据有两个途径。
是从上下文中直接获取 请求对象ctx.query,返回如 { a:1, b:2 } 请求字符串 ctx.querystring,返回如 a=1&b=2
是从上下文的request对象中获取 请求对象ctx.request.query,返回如 { a:1, b:2 } 请求字符串 ctx.request.querystring,返回如 a=1&b=2
2、举个例子
2.1 例子代码
constKoa=require('koa')constapp=newKoa()app.use(async(ctx)=>{leturl=ctx.url// 从上下文的request对象中获取letrequest=ctx.requestletreq_query=request.queryletreq_querystring=request.querystring// 从上下文中直接获取letctx_query=ctx.queryletctx_querystring=ctx.querystring ctx.body={url,req_query,req_querystring,ctx_query,ctx_querystring}})app.listen(3000,()=>{console.log('[demo] request get is starting at port 3000')})
2.2 执行程序
node get.js
二、POST请求参数获取
1、原理
对于POST请求的处理,koa2没有封装获取参数的方法,需要通过解析上下文context中的原生node.js请求对象req,将POST表单数据解析成query string(例如:a=1&b=2&c=3),再将query string 解析成JSON格式(例如:{"a":"1", "b":"2", "c":"3"})
注意:ctx.request是context经过封装的请求对象,ctx.req是context提供的node.js原生HTTP请求对象,同理ctx.response是context经过封装的响应对象,ctx.res是context提供的node.js原生HTTP请求对象。
解析出POST请求上下文中的表单数据
// 解析上下文里node原生请求的POST参数functionparsePostData(ctx){returnnewPromise((resolve,reject)=>{try{letpostdata="";ctx.req.addListener('data',(data)=>{postdata+=data})ctx.req.addListener("end",function(){letparseData=parseQueryStr(postdata)resolve(parseData)})}catch(err){reject(err)}})}// 将POST请求参数字符串解析成JSONfunctionparseQueryStr(queryStr){letqueryData={}letqueryStrList=queryStr.split('&')console.log(queryStrList)for(let[index,queryStr]ofqueryStrList.entries()){letitemList=queryStr.split('=')queryData[itemList[0]]=decodeURIComponent(itemList[1])}returnqueryData}
2、举个例子
2.1 例子代码
constKoa=require('koa')constapp=newKoa()app.use(async(ctx)=>{if(ctx.url==='/'&&ctx.method==='GET'){// 当GET请求时候返回表单页面lethtml=` <h1>koa2 request post demo</h1>
<form method="POST" action="/">
<p>userName</p>
<input name="userName" /><br/>
<p>nickName</p>
<input name="nickName" /><br/>
<p>email</p>
<input name="email" /><br/>
<button type="submit">submit</button>
</form>
`ctx.body=html}elseif(ctx.url==='/'&&ctx.method==='POST'){// 当POST请求的时候,解析POST表单里的数据,并显示出来letpostData=awaitparsePostData(ctx)ctx.body=postData}else{// 其他请求显示404ctx.body='<h1>404!!! o(╯□╰)o</h1>'}})// 解析上下文里node原生请求的POST参数functionparsePostData(ctx){returnnewPromise((resolve,reject)=>{try{letpostdata="";ctx.req.addListener('data',(data)=>{postdata+=data})ctx.req.addListener("end",function(){letparseData=parseQueryStr(postdata)resolve(parseData)})}catch(err){reject(err)}})}// 将POST请求参数字符串解析成JSONfunctionparseQueryStr(queryStr){letqueryData={}letqueryStrList=queryStr.split('&')console.log(queryStrList)for(let[index,queryStr]ofqueryStrList.entries()){letitemList=queryStr.split('=')queryData[itemList[0]]=decodeURIComponent(itemList[1])}returnqueryData}app.listen(3000,()=>{console.log('[demo] request post is starting at port 3000')})
2.2 启动例子
node post.js
三、koa-bodyparser中间件
1、原理
对于POST请求的处理,koa-bodyparser中间件可以把koa2上下文的formData数据解析到ctx.request.body中
安装koa2版本的koa-bodyparser@3中间件
npm install --save koa-bodyparser@3
2、举个例子
2.1 例子代码
constKoa=require('koa')constapp=newKoa()constbodyParser=require('koa-bodyparser')// 使用ctx.body解析中间件app.use(bodyParser())app.use(async(ctx)=>{if(ctx.url==='/'&&ctx.method==='GET'){// 当GET请求时候返回表单页面lethtml=` <h1>koa2 request post demo</h1>
<form method="POST" action="/">
<p>userName</p>
<input name="userName" /><br/>
<p>nickName</p>
<input name="nickName" /><br/>
<p>email</p>
<input name="email" /><br/>
<button type="submit">submit</button>
</form>
`ctx.body=html}elseif(ctx.url==='/'&&ctx.method==='POST'){// 当POST请求的时候,中间件koa-bodyparser解析POST表单里的数据,并显示出来letpostData=ctx.request.body ctx.body=postData}else{// 其他请求显示404ctx.body='<h1>404!!! o(╯□╰)o</h1>'}})app.listen(3000,()=>{console.log('[demo] request post is starting at port 3000')})
2.2 启动例子
node post-middleware.js
Ⅳ、静态资源加载
koa-static中间件使用
1、使用例子
constKoa=require('koa')constpath=require('path')conststatic=require('koa-static')constapp=newKoa()// 静态资源目录对于相对入口文件index.js的路径conststaticPath='./static'app.use(static(path.join(__dirname,staticPath)))app.use(async(ctx)=>{ctx.body='hello world'})app.listen(3000,()=>{console.log('[demo] static-use-middleware is starting at port 3000')})
Ⅴ、模板引擎
koa2加载模板引擎
1、快速开始
1.1 安装模块
# 安装koa模板使用中间件npm install --save koa-views# 安装ejs模板引擎npm install --save ejs
1.2 使用模板引擎
文件目录
├── package.json├── index.js└── view └── index.ejs
./index.js文件
constKoa=require('koa')constviews=require('koa-views')constpath=require('path')constapp=newKoa()// 加载模板引擎app.use(views(path.join(__dirname,'./view'),{extension:'ejs'}))app.use(async(ctx)=>{lettitle='hello koa2'awaitctx.render('index',{title,})})app.listen(3000)
./view/index.ejs 模板
<!DOCTYPE html><html><head><title><%= title %></title></head><body><h1><%= title %></h1><p>EJS Welcome to <%= title %></p></body></html>
0人点赞
作者:硅谷干货
链接:https://www.jianshu.com/p/920ad3e248ec
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。