目的
Node.js最基本的是用来搭建HTTP服务器使用,它内置的模块基本上可以满足基础的HTTP服务器功能,但是如果要实现比较完整的HTTP服务器功能体验的话开发者还需要编写更多的代码。所以通常使用的话可以选择现成的框架,Koa就是一个现在比较流行的框架。这篇文章将对Koa使用做个入门介绍。
Koa 通过 node.js 实现了一个十分具有表现力的 HTTP 中间件框架,力求让 Web 应用开发和 API 使用更加地愉快。Koa 的中间件之间按照编码顺序在栈内依次执行,允许您执行操作并向下传递请求(downstream),之后过滤并逆序返回响应(upstream)。
几乎所有 HTTP 服务器通用的方法都被直接集成到 Koa 大约570行源码的代码库中。其中包括内容协商,节点不一致性的规范化,重定向等等操作。
Koa没有捆绑任何中间件。
官网地址:https://koajs.com/
项目地址:https://github.com/koajs/koa
基础介绍
Koa 依赖 Node.js v7.6.0 或 ES2015及更高版本和 async 方法支持,在安装了Node.js、建立并初始化项目后就可以使用npm安装Koa:npm install koa
,目前Koa版本为 2.13.4
。
下面是个最基本的Koa使用:
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
Koa最重要的一点就是它是一个 HTTP 中间件框架
,这是Koa最重要的一点,只要理解这点Koa就算入门了。Koa是基于HTTP功能的,首先看下Node.js中http模块的使用:
上面的演示和前面Koa的演示结构上是很像的,无非就是编写相应的HTTP请求处理方法,然后启动监听,我们写代码主要就是关注于中间处理部分。事实上前面的Koa演示的代码也可以写成下面这样:
const http = require('http');
const Koa = require('koa');
const app = new Koa();
app.use(ctx => {
ctx.body = 'Hello Koa';
});
http.createServer(app.callback()).listen(3000); // 相当于 app.listen(3000);
到这里就可以认识到Koa就是在http模块模块的基础上接管了来自客户端的HTTP请求,接下来所有操作就都是在Koa的基础上进行了。
Koa对象的use方法中可以传入回调函数用来处理来自客户端的HTTP请求,该回调函数可以传入两个参数,依次通常写作 ctx
、 next
。 ctx
可以看成是HTTP请求和响应的整体封装,而 next
为下一步的异步处理。
Koa对于每个HTTP请求都可以分为多步来处理, 也就是多可以有多个 app.use()
,实际处理时按照调用 app.use()
的先后顺序执行,并且在每个 app.use()
的回调函数中又可以以异步方式调用下一步处理。下面是个简单的演示:
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
console.log('1');
await next();
console.log('5');
});
app.use(async (ctx, next) => {
console.log('2');
await next();
console.log('4');
});
app.use(ctx => {
console.log('3');
ctx.body = 'Hello Koa';
});
app.listen(3000);
Koa的对象除了上面出现的 use() 、 listen() 、 callback() 方法外,常用的还有 keys 、 context 对象 和 错误处理。 keys
对象用于设置 signed cookie keys,比如下面两种方式:
app.keys = ['im a newer secret', 'i like turtle'];
app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256');
context
对象是我们最常用的对象了,一般在使用时变量名为 ctx ,它封装了http请求和响应等内容。你也可以向其中添加属性共全局使用。 context
对象内容比较多,将再下一节单独介绍。
错误处理相关内容将在再下面一节进行介绍。
Koa提供的功能几乎就是上面介绍的这些部分了,它本身提供的功能并不多,很多功能都需要依靠各种中间件来实现。Koa的中间件就是一个个的函数,在 app.use() 中被调用。根据Koa的机制,每个HTTP请求可以使用多个中间件分步进行处理。
Koa Context
Koa的 context
对象是我们最常用的对象,一般在使用时变量名为 ctx
,它封装了http请求和响应等内容,比如 ctx.req 就是 Node.js HTTP模块的 request 对象,ctx.res 就是 Node.js HTTP模块的 response 对象。 context
对象可用的一些属性和方法如下:
属性和方法 |
说明 |
备注 |
req |
Node.js HTTP模块的 request 对象 |
|
res |
Node.js HTTP模块的 response |
不支持以下属性和方法: res.statusCode res.writeHead() res.write() res.end() |
request |
Koa 的 Request 对象 |
|
response |
Koa 的 Response 对象 |
|
state |
推荐的用于全局传递数据的命名空间 |
|
app |
Koa应用的实例引用 |
|
cookies.get(name, [options]) |
获得 cookie 中名为 name 的值,options 为可选参数 |
例:ctx.cookies.get(‘name’, { signed: true }); signed 为 true,表示需要密钥 |
cookies.set(name, value, [options]) |
设置 cookie 中名为 name 的值,options 为可选参数 |
|
throw([status], [msg], [properties]) |
抛出异常 |
|
assert(value, [status], [msg], [properties]) |
当 !value 时抛出类似于throw()方式的错误 |
|
respond |
时用res时可以设置respond = false |
不推荐 |
Request
Koa Request 对象是对 node 的 request 进一步抽象和封装,提供了日常 HTTP 服务器开发中一些有用的功能。Koa Request 大多数属性支持简写,比如 ctx.request.headers
等价于 ctx.headers
。
属性和方法 |
说明 |
备注 |
header / header= headers / headers= |
获取 / 设置 请求头对象 |
|
method / method= |
获取 / 设置 请求方法 |
|
length |
返回Content-Length数值 |
|
url / url= |
获取 / 设置 url |
|
originalUrl |
获取请求原始URL |
|
origin |
获取原始URL,包含 protocol 和 host |
|
href |
获取完整的请求URL, 包含 protocol, host 和 url |
|
path / path= |
获取 / 设置 请求路径(保留当前查询字符串) |
|
querystring / querystring= |
获取 / 设置 原始查询字符串(不包含?) |
|
search / search= |
获取 / 设置 原始查询字符串(包含?) |
|
host |
获取host(hostname:port) |
|
hostname |
获取 hostname |
|
URL |
获取 WHATWG 解析的URL对象 |
|
type |
获取请求 Content-Type |
|
charset |
获取请求 charset,没有则返回 undefined: |
|
query |
将查询参数字符串进行解析并以对象的形式返回 如果没有查询参数字字符串则返回一个空对象 |
|
query= |
根据给定的对象设置查询参数字符串 |
|
fresh |
检查请求缓存是否 “fresh”(内容没有发生变化) |
|
stale |
与 fresh 相反 |
|
protocol |
返回请求协议,“https” 或者 “http” |
|
secure |
简化版 protocol == “https”,用来检查请求是否通过 TLS 发送 |
|
ip |
返回请求远程ip地址 |
|
ips |
返回路径上依次的ip地址 |
|
subdomains |
以数组形式返回子域名 |
|
is(types…) |
检查请求所包含的 “Content-Type” 是否为给定的 type 值, 如果没有 request body,返回 undefined, 如果没有 content type,或者匹配失败,返回 false, 否则返回匹配的 content-type |
|
accepts(types) |
检查给定的类型 types(s) 是否可被接受,当为 true 时返回最佳匹配,否则返回 false |
|
acceptsEncodings(encodings) |
检查 encodings 是否可以被接受,当为 true 时返回最佳匹配,否则返回 false |
|
acceptsCharsets(charsets) |
检查 charsets 是否可以被接受,如果为 true 则返回最佳匹配, 否则返回 false |
|
acceptsLanguages(langs) |
检查 langs 是否可以被接受,如果为 true 则返回最佳匹配,否则返回 false |
|
idempotent |
检查请求是否为幂等 |
|
socket |
返回请求的socket |
|
get(field) |
返回请求头 |
|
Response
Koa Response 对象是对 node 的 response 进一步抽象和封装,提供了日常 HTTP 服务器开发中一些有用的功能。Koa Response 大多数属性支持简写,比如 ctx.response.body
等价于 ctx.body
。
属性和方法 |
说明 |
备注 |
header / headers |
响应头对象 |
不支持简写 |
socket |
响应socket |
不支持简写 |
status / status= |
获取 / 设置 响应状态,默认为404 |
|
message / message= |
获取 / 设置 响应状态消息 |
|
length / length= |
获取 / 设置 响应 Content-Length 数值,没有则返回undefined |
|
body / body= |
获取 / 设置 响应正文 |
|
get(field) / set(field, value) |
获取 / 设置 响应头中字段 |
|
append(field, value) |
向响应头添加额外字段 |
|
set(fields) |
使用对象设置响应头多个字段 |
|
remove(field) |
移除响应头中的字段 |
|
type / type= |
获取 / 设置 Content-Type |
|
is(types…) |
检查响应类型是否是所提供的类型之一 |
不支持简写 |
redirect(url, [alt]) |
执行 [302] 重定向到对应 url |
|
attachment([filename]) |
设置 “attachment” 的 Content-Disposition,用于给客户端发送信号来提示下载, filename 为可选参数,用于指定下载文件名 |
|
headerSent |
检查 response header 是否已经发送,用于在发生错误时检查客户端是否被通知 |
|
lastModified / lastModified= |
获取 / 设置 lastModified |
|
etag= |
设置 包含 "s 的 ETag |
|
vary(field) |
|
不支持简写 |
flushHeaders() |
|
不支持简写 |
错误处理
Koa对象可以使用下面的方式捕获异常:
app.on('error', err => {
console.error('error', err);
});
// 错误发生在 请求/响应 环节
app.on('error', (err, ctx) => {
console.error('error', err, ctx)
});
对于发生在 请求/响应 环节的错误也可以使用 try { } catch { }
进行捕获,这种方式捕获的错误不会再传递给上面的onerror事件,如果有需求可以使用Koa对象的emit()方法释放捕获的错误:
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
console.error('error', err);
ctx.app.emit('error', err, ctx);
}
});
在 请求/响应 环节中可以使用 throw([status], [msg], [properties])
来抛出异常。
下面是个错误处理的演示:
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
console.error('error 1', err);
ctx.app.emit('error', err, ctx);
}
});
app.use(ctx => {
ctx.throw(500);
});
app.on('error', (err, ctx) => {
console.error('error 2', err)
});
app.listen(3000);
总结
本篇文章基本介绍完了Koa本体所涉及的大部分功能,Koa是一个中间件框架,主要提供的功能也并不多,更多Web服务器常用的功能比如 路由、静态文件、模板 等功能都需要通过中间件来提供。接下来的文章会介绍些常用的中间件及使用方法 —— 《Koa笔记 02:常用中间件》。