(贴个官网,koa 内容真不多,非常的小巧轻量)
1. koa 是什么
一个更小、更富有表现力、更健壮的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。
基础样例:
const koa = require("koa");
const app = new koa(); // express 不用 new,是 const app = express();
app.use(async (ctx, next) => { // 为应用添加指定的中间件
console.log(ctx.request.path); // 打印请求的 url 路径部分
// ctx.response.body = "<b>Hello World</b>"; // 设置响应体
// ctx.response.body = "Hello World"; // 设置响应体
ctx.response.body = {name: "bob"}; // 设置响应体
})
app.listen(3000); // 监听 3000 端口
2. ctx 参数
该 context 在每个 request 请求中被创建,在中间件中作为接收器来引用,或者通过 this 标识符来引用,其身上几个重要的属性:
- ctx.req:Node 的 request 对象
- ctx.res:Node 的 response 对象
- ctx.request:Koa 的 Request 对象
- ctx.response:Koa 的 Response 对象
- ctx.cookies.get(name, [options]):获得 cookie 中名为 name 的值,options 为可选参数
- ctx.cookies.set(name, value, [options]):设置 cookie 中名为 name 的值,options 为可选参数
- ctx.throw([status], [msg], [properties]):抛出包含 .status 属性的错误,默认为 500。该方法可以让 Koa 准确的响应处理状态,例 ctx.throw(400, ‘name required’, { user: user });
【注:app.context 是从中创建 ctx 的原型。 可以通过编辑 app.context 向 ctx 添加其他属性,当需要将 ctx 添加到整个应用程序中使用的属性或方法时,这将会非常有用。例,向 ctx 中添加对数据库的引用】
app.context.db = db();
app.use(async ctx => {
console.log(ctx.db);
});
【注:许多 context 的访问器和方法为了便于访问和调用,简单的委托给他们的 ctx.request 和 ctx.response 所对应的等价方法, 比如说 ctx.type,ctx.length,ctx.body 代理了 response 对象中对应的方法,ctx.path,ctx.method,ctx.header 代理了 request 对象中对应的方法】
3. next 参数
当执行到 next 语句时,Koa 暂停了该中间件,继续执行下一个符合请求的中间件,执行完后,然后将控制权再逐级返回给上层中间件
下面的例子在页面中返回 “Hello World”,然而当请求开始时,请求先经过 x-response-time 和 logging 中间件,并记录中间件执行起始时间。 然后将控制权交给 reponse 中间件。当一个中间件调用next()函数时,函数挂起并控件传递给定义的下一个中间件。在没有更多的中间件执行下游之后,堆栈将退出,并且每个中间件被恢复以执行其上游行为
const Koa = require('koa');
const app = new Koa();
// x-response-time
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
// logger
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});
// response
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
4. request 对象
Koa Request 对象是对 node 的 request 进一步抽象和封装,提供了日常 HTTP 服务器开发中一些有用的功能,常用api有:
- request.header:获得或设置请求头对象(request.headers 等价)
- request.method:获得或设置请求方法
- request.length:以数字的形式返回 request 的内容长度(Content-Length),或者返回 undefined
- request.url:获得或设置请求 url 地址
- request.href:获取完整的请求URL, 包含 protocol, host 和 url
- request.path:获取请求路径名,或设置请求路径名并保留当前查询字符串
- request.querystring:获取查询参数字符串(url中?后面的部分,不包含?),或设置原始查询字符串
- request.search:获取查询参数字符串(包含?),或设置原始查询字符串
- request.type:获取请求 Content-Type,不包含像 “charset” 这样的参数
- request.is(types…): 检查请求所包含的 “Content-Type” 是否为给定的 type 值。 如果没有 request body,返回 undefined。 如果没有 content type,或者匹配失败,返回 false。 否则返回匹配的 content-type
// When Content-Type is application/json ctx.is('json', 'urlencoded'); // => 'json' ctx.is('application/json'); // => 'application/json' ctx.is('html', 'application/*'); // => 'application/json' ctx.is('html'); // => false
- request.charset:获取请求 charset(例"utf-8"),没有则返回 undefined
- request.query:将查询参数字符串进行解析并以对象的形式返回,如果没有查询参数字字符串则返回一个空对象,或根据给定的对象设置查询参数字符串。注意,该方法不支持嵌套解析
- request.fresh:检查请求缓存是否 “fresh”(内容没有发生变化)。该方法用于在 If-None-Match / ETag, If-Modified-Since 和 Last-Modified 中进行缓存协调。当在 response headers 中设置一个或多个上述参数后,该方法应该被使用
- request.stale:与 req.fresh 相反
- request.protocol:返回请求协议,“https” 或者 “http”。 当 app.proxy 设置为 true 时,支持 X-Forwarded-Host
- request.socket:返回请求的 socket
- request.get(field):返回请求头中 field 字段的值
5. response 对象
Koa Response 对象是对 node 的 response 进一步抽象和封装,提供了日常 HTTP 服务器开发中一些有用的功能,常用api有:
- response.socket:响应套接字(套接字就是 socket),作为 request.socket 指向 net.Socket 实例
- response.header:响应头对象(response.headers 等价)
- response.status:获取响应状态(默认情况下,response.status设置为404,而不像node’s res.statusCode默认为200),或通过数字设置响应状态
- response.message:获取响应状态消息(默认情况下, response.message关联response.status),或将响应状态消息设置为给定值
- response.body:获取响应体,或设置响应体(如果此时 res.status 没有赋值,Koa会自动设置为 200 或 204)
- response.length:以数字返回响应的 Content-Length,或者从ctx.body推导出来,或者undefined,或将响应的 Content-Length 设置为给定值
- response.set(field, value):设置 response header 字段 field 的值为 value
- response.append(field, value):添加额外的字段 field 的值为 val
- response.set(fields):使用对象同时设置 response header 中多个字段的值
- response.remove(field):移除 response header 中字段 filed
- response.type:获取 response Content-Type,不包含像"charset"这样的参数,或通过 mime 类型的字符串或者文件扩展名设置 response Content-Type
- response.redirect(url, [alt]):执行 [302] 重定向到 url,如果想要修改默认的 [302] 状态码,直接在重定向之前或者之后执行即可。如果要修改 body,需要在重定向之前执行
【字符串 “back” 是特殊参数,其提供了 Referrer 支持。当没有 Referrer 时,使用 alt 或者 / 代替】ctx.redirect('back'); ctx.redirect('back', '/index.html'); ctx.redirect('/login'); ctx.redirect('http://google.com');
- response.headerSent:检查 response header 是否已经发送,用于在发生错误时检查客户端是否被通知
- response.lastModified:如果存在 Last-Modified,则以 Date 的形式返回,或以 UTC 格式设置 Last-Modified,可以使用 Date 或 date 字符串来进行设置
6. koa1,koa2 和 express 的区别
- 实现异步方式不同,koa1 实现异步是通过 generator/yield,koa2 实现异步是通过 async/awaite,而 express 实现异步是通过回调函数的方式
- express 是大而全,内置了大多数的中间件,更让人省心,koa2 不绑定任何的框架,干净简洁,小而精,更容易实现定制化,扩展性好,koa 中想实现 express 很多功能需要借助第三方中间件解决
- express 本身是不支持洋葱模型的数据流入流出能力的(类似于线型),需要引入其他的插件,而在 koa 中,一切的流程都是中间件,数据流向遵循洋葱模型,先入后出,是按照类似堆栈的方式组织和执行的,koa 的数据流入流出,next() 后,会进入下一个中间件并执行,然后从最后一个中间件反向执行
const Koa = require('koa') const app = new Koa() const mid1 = async (ctx, next) => { ctx.body = '前:' + '1\n' await next() ctx.body = ctx.body + '后:' + '1\n' } const mid2 = async (ctx, next) => { ctx.body = ctx.body + '前:'+ '2\n' await next() ctx.body = ctx.body + '后:'+ '2\n' } const mid3 = async (ctx, next) => { ctx.body = ctx.body + '前:'+ '3\n' await next() ctx.body = ctx.body + '后:'+ '3\n' } app.use(mid1) app.use(mid2) app.use(mid3) app.listen(3000) // 前1 // 前2 // 前3 // 后3 // 后2 // 后1
- koa 新增 context 对象,作为这次请求的上下文对象,除了提供了大量便捷的 api 辅助开发,还可以在其上面保存一些公有的参数数据来使用