介绍熟悉SpringMVC的朋友应该知道,SpringMVC是一个基于servlet的代码框架,是最传统的web框架。然后在Spring5中引入了SpringWebFlux,它是一个基于reactive-netty的异步IO框架。同样,nodejs在原有Express3的基础上开发了异步koa框架,koa使用promises和aysnc来避免JS中的回调地狱,简化错误处理。今天我们就来介绍一下这个优秀的nodejs框架koa。koa和expresskoa不再使用nodejs的req和res,而是封装了自己的ctx.request和ctx.response。Express可以看作是nodejs的一个应用框架,而koa可以看作是nodejs的http模块的抽象。与express提供中间件、路由、模板、发送文件、JSONP等功能不同,koa的功能单一。如果想使用路由、发送文件等其他功能,可以使用koa的第三方中间件。Koa不是用来代替express,就像springwebFlux不是用来代替springMVC一样。Koa只是用Promises重写了控制流,避免了回调地狱,提供了更好的异常处理机制。koa介绍koa需要nodev7.6.0+版本支持ES2015和async功能。让我们看一个最简单的koa应用程序:constKoa=require('koa');constapp=module.exports=newKoa();app.use(asyncfunction(ctx){ctx.body='HelloWorld';});如果(!module.parent)app.listen(3000);一个koa应用是一个包含很多中间件的对象,这些中间件会按照类似栈的执行顺序执行相应的请求。中间件的级联关系koa.use中的输入是一个函数,我们也可以称之为中间件。Koa可以使用很多中间件,例如:constKoa=require('koa');constapp=newKoa();app.use(async(ctx,next)=>{awaitnext();console.log('log3');});app.use(async(ctx,next)=>{awaitnext();console.log('log2');});app.use(asyncctx=>{console.log('log3');});app.listen(3000);在上面的例子中,我们多次调用了next,只要调用了next,调用链就会传递给下一个中间件进行处理,直到有一个中间件不再调用next为止。上面代码运行的输出:log1log2log3koaconstructor我们来看一下koa的构造函数:constructor(options){super();选项=选项||{};this.proxy=options.proxy||错误的;this.subdomainOffset=options.subdomainOffset||2;this.proxyIpHeader=options.proxyIpHeader||'X-Forwarded-For';this.maxIpsCount=options.maxIpsCount||0;this.env=options.env||进程.env.NODE_ENV||'发展';如果(options.keys)this.keys=options.keys;这个.middleware=[];this.context=Object.create(context);this.request=Object.create(请求);这。响应=Object.create(响应);//util.inspect.custom支持节点6+/*istanbulignoreelse*/if(util.inspect.custom){this[util.inspect.custom]=this.inspect;可以看到koa接收到如下参数:app.env默认值为NODE_ENV或者developmentapp.keys为cookie签名的keys看使用方法:app.keys=['secret1','secret2'];app.keys=newKeyGrip(['secret1','secret2'],'sha256');ctx.cookies.set('name','jack',{signed:trUE});app.proxy是否支持代理app.subdomainOffset表示子域从哪一级开始,该参数决定了request.subdomains的返回结果,默认值为2app.proxyIpHeader代理ip头默认值为X-Forwarded-Forapp.maxIpsCount的从代理ip标头读取的最大ips数,默认值为0表示无限制我们可以使用:constKoa=require('koa');constapp=newKoa({proxy:true});或者这样使用:constKoa=require('koa');constapp=newKoa();app.proxy=true;启动http服务器Koa是一个web框架,web框架需要开启http服务。启动http服务需要调用nodejs中的Server#listen()方法。在koa中,我们可以很容易地使用koa#listen方法来启动这个http服务器:constKoa=require('koa');constapp=newKoa();app.listen(3000);上面的代码等同于:consthttp=require('http');constKoa=require('koa');constapp=newKoa();http.createServer(app.callback()).listen(3000);当然,您可以同时为http和https创建服务:consthttp=require('http');consthttps=require('https');constKoa=require('koa');constapp=newKoa();http.createServer(app.callback()).listen(3000);https.createServer(app.callback()).listen(3001);自定义中间件koa中的中间件是一个函数,其参数值为(ctx,next)。在这些方法中,需要手动调用next()以传递给下一个中间件。让我们看一下自定义中间件:asyncfunctionresponseTime(ctx,next){conststart=Date.now();等待下一个();constms=Date.now()-开始;ctx.set('X-Response-Time',`${ms}ms`);}app.use(responseTime);给中间件起个名字:虽然中间件函数只接收参数(ctx,next),但我可以用它和包装器一起使用在包装器方法中,我们给中间件起个名字:functionlogger(name){returnasyncfunctionlogger(ctx,下一个){console.log(名称);等待下一个();};}自定义中间件扩展:上面的wrapper创建方式还有一个好处,就是可以在自定义中间件中访问传入的参数,从而可以根据传入的参数对自定义中间件进行扩展。函数记录器(格式){格式=格式||':方法“:url”';returnasyncfunction(ctx,next){conststr=format.replace(':method',ctx.method).replace(':url',ctx.url);控制台日志(海峡);等待下一个();};}app.use(logger());app.use(logger(':method:url'));组合多个中间件:当有多个中间件的情况下,我们可以使用compose将其合并:constcompose=require('koa-compose');constKoa=require('koa');constapp=module.exports=newKoa();//x-response-timeasyncfunctionresponseTime(ctx,next){conststart=newDate();等待下一个();constms=newDate()-开始;ctx.set('X-Response-Time',ms+'ms');}//loggerasync函数logger(ctx,next){conststart=newDate();等待下一个();constms=newDate()-开始;if('test'!=process.env.NODE_ENV){console.log('%s%s-%s',ctx.method,ctx.url,ms);}}//responseasync函数respond(ctx,next){awaitnext();如果('/'!=ctx.url)返回;ctx.body='HelloWorld';}//组成中间件constall=compose([responseTime,logger,respond]);app.use(all);if(!module.parent)app.listen(3000);异常处理koa中如何处理异常?一般的方法是trycatch:app.use(async(ctx,next)=>{try{awaitnext();}catch(err){err.status=err.statusCode||err.status||500;throw呃;}});当然你也可以自定义默认的错误处理器:app.on('error',err=>{log.error('servererror',err)});我们也可以传入上下文信息:app.on('error',(err,ctx)=>{log.error('servererror',err,ctx)});本文作者:Flydeanprogramthosethings本文链接:http://www.flydean.com/koa-startup/本文来源:flydean的博客欢迎关注我的公众号:《程序》最通俗的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等等,快来一探究竟吧!
