简介
相熟Spring MVC的敌人应该都分明Spring MVC是基于servlet的代码框架,这是最传统的web框架。而后在Spring5中引入了Spring WebFlux,这是基于reactive-netty的异步IO框架。
同样的,nodejs在最后的Express 3根底上倒退起来了异步的koa框架。koa应用了promises和aysnc来防止JS中的回调天堂,并且简化了错误处理。
明天咱们要来介绍一下这个优良的nodejs框架koa。
koa和express
koa不再应用nodejs的req和res,而是封装了本人的ctx.request和ctx.response。
express能够看做是nodejs的一个利用框架,而koa则能够看成是nodejs 的http模块的形象。
和express提供了Middleware,Routing,Templating,Sending Files和JSONP等个性不同的是,koa的性能很繁多,如果你想应用其余的一些性能比方routing,sending files等性能,能够应用koa的第三方中间件。
koa并不是来替换express的,就像spring webFlux并不是用来替换spring MVC的。koa只是用Promises改写了控制流,并且防止了回调天堂,并提供了更好的异样解决机制。
koa应用介绍
koa须要node v7.6.0+版本来反对ES2015和async function。
咱们看一个最最简略的koa利用:
const Koa = require('koa');
const app = module.exports = new Koa();
app.use(async function(ctx) {
ctx.body = 'Hello World';
});
if (!module.parent) app.listen(3000);
koa应用程序就是一个蕴含了很多个中间件的对象,这些中间件将会依照相似stack的执行程序一个相应request。
中间件的级联关系
koa.use中传入的是一个function,咱们也能够称之为中间件。
koa能够use很多个中间件,举个例子:
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
await next();
console.log('log3');
});
app.use(async (ctx, next) => {
await next();
console.log('log2');
});
app.use(async ctx => {
console.log('log3');
});
app.listen(3000);
下面的例子中,咱们调用了屡次next,只有咱们调用next,调用链就会传递到下一个中间件进行解决,始终到某个中间件不再调用next
为止。
下面的代码运行输入:
log1
log2
log3
koa的构造函数
咱们看下koa的构造函数:
constructor(options) {
super();
options = options || {};
this.proxy = options.proxy || false;
this.subdomainOffset = options.subdomainOffset || 2;
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
this.maxIpsCount = options.maxIpsCount || 0;
this.env = options.env || process.env.NODE_ENV || 'development';
if (options.keys) this.keys = options.keys;
this.middleware = [];
this.context = Object.create(context);
this.request = Object.create(request);
this.response = Object.create(response);
// util.inspect.custom support for node 6+
/* istanbul ignore else */
if (util.inspect.custom) {
this[util.inspect.custom] = this.inspect;
}
}
能够看到koa接管上面几个参数:
- app.env 默认值是NODE_ENV或者development
- app.keys 为cookie签名的keys
看下怎么应用:
app.keys = ['secret1', 'secret2'];
app.keys = new KeyGrip(['secret1', 'secret2'], 'sha256');
ctx.cookies.set('name', 'jack', { signed: true });
- app.proxy 是否反对代理
- app.subdomainOffset 示意子域名是从第几级开始的,这个参数决定了request.subdomains的返回后果,默认值为2
- app.proxyIpHeader proxy ip header默认值是X-Forwarded-For
- app.maxIpsCount 从proxy ip header读取的最大ip个数,默认值是0示意无限度。
咱们能够这样用:
const Koa = require('koa');
const app = new Koa({ proxy: true });
或者这样用:
const Koa = require('koa');
const app = new Koa();
app.proxy = true;
启动http server
koa是一种web框架,web框架就须要开启http服务,要启动http服务,须要调用nodejs中的Server#listen()办法。
在koa中,咱们能够很不便的应用koa#listen办法来启动这个http server:
const Koa = require('koa');
const app = new Koa();
app.listen(3000);
下面的代码相当于:
const http = require('http');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
当然你能够同时创立http和https的服务:
const http = require('http');
const https = require('https');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
https.createServer(app.callback()).listen(3001);
自定义中间件
koa中的中间件是参数值为(ctx, next)的function。在这些办法中,须要手动调用next()以传递到下一个middleware。
上面看一下自定义的中间件:
async function responseTime(ctx, next) {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
}
app.use(responseTime);
- 给中间件起个名字:
尽管中间件function只接管参数(ctx, next),然而我能够将其用一个wrapper办法包装起来,在wrapper办法中,咱们给中间件起个名字 :
function logger(name) {
return async function logger(ctx, next) {
console.log(name);
await next();
};
}
- 自定义中间件的扩大:
下面的wrapper创立形式还有另外一个益处,就是能够在自定义中间件中拜访传入的参数,从而能够依据传入的参数,对自定义中间件进行扩大。
function logger(format) {
format = format || ':method ":url"';
return async function (ctx, next) {
const str = format
.replace(':method', ctx.method)
.replace(':url', ctx.url);
console.log(str);
await next();
};
}
app.use(logger());
app.use(logger(':method :url'));
- 组合多个中间件:
当有多个中间件的状况下,咱们能够应用compose将其合并:
const compose = require('koa-compose');
const Koa = require('koa');
const app = module.exports = new Koa();
// x-response-time
async function responseTime(ctx, next) {
const start = new Date();
await next();
const ms = new Date() - start;
ctx.set('X-Response-Time', ms + 'ms');
}
// logger
async function logger(ctx, next) {
const start = new Date();
await next();
const ms = new Date() - start;
if ('test' != process.env.NODE_ENV) {
console.log('%s %s - %s', ctx.method, ctx.url, ms);
}
}
// response
async function respond(ctx, next) {
await next();
if ('/' != ctx.url) return;
ctx.body = 'Hello World';
}
// composed middleware
const all = compose([
responseTime,
logger,
respond
]);
app.use(all);
if (!module.parent) app.listen(3000);
异样解决
在koa中怎么进行异样解决呢?
通用的办法就是try catch:
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
err.status = err.statusCode || err.status || 500;
throw err;
}
});
当然你也能够自定义默认的error处理器:
app.on('error', err => {
log.error('server error', err)
});
咱们还能够传入上下文信息:
app.on('error', (err, ctx) => {
log.error('server error', err, ctx)
});
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/koa-startup/
本文起源:flydean的博客
欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
发表回复