简洁而强大的 web 框架。
Thanks to Koa and it's authors
Toa 修改自 Koa,基本架构原理与 Koa 相似,context
、request
、response
三大基础对象几乎一样。
Toa 是基于 thunks 组合业务逻辑,来实现异步流程控制和异常处理。thunks
是一个比 co
更强大的异步流程控制工具,支持所有形式的异步控制,包括 callback,promise,generator,async/await 等。
Toa 支持 Node.js v0.12
以上,但在高版本中将有更好的体验和性能,如 >=v4
的版本支持 generator 函数,>=v7
的版本支持 async/await 函数,这些特性支持用同步逻辑编写非阻塞的异步程序。
Toa 与 Koa 学习成本和编程体验是一致的,两者之间几乎是无缝切换。但 Toa 去掉了 Koa 的 级联(Cascading)
逻辑,强化中间件,尽量削弱第三方组件访问应用的能力,使得编写大型应用的结构逻辑更简洁明了,也更安全。
npm install toa
一个 Toa Application(以下简称 app)由一系列 中间件 组成。中间件 是指通过 app.use
加载的同步函数、thunk 函数、generator 函数或 async/await 函数。
对于 web server 的一次访问请求,app 会按照顺序先运行中间件,然后再运行业务逻辑中 context.after(hook)
动态添加的 hooks,最后运行内置的 respond
函数,将请求结果自动响应的客户端。由于 Toa 没有 级联(Cascading)
,这些中间件或模块的运行不会有任何交叉,它们总是先运行完一个,再运行下一个。
Toa 只有一个极简的内核,提供快捷的 HTTP 操作和异步流程控制能力。具体的业务功能逻辑则由中间件和模块组合实现。用户则可根据自己的业务需求,以最轻量级的方式组合自己的应用。
让我们来看看 Toa 极其简单的 Hello World 应用程序:
const Toa = require('toa')
const app = new Toa()
app.use(function () {
this.body = 'Hello World!\n-- toa'
})
app.listen(3000)
server
: {Object}, http server 或 https server 实例。options
: {Object} 类似thunks
的 options,对于 server 的每一个 client request,toa app 均会用thunks
生成一个的thunk
,挂载到context.thunk
,该thunk
的作用域对该 client request 的整个生命周期生效。options.onerror
: {Function} 其this
为 client request 的context
对象。当 client request 处理流程出现异常时,会抛出到onerror
,原有处理流程会终止,onerror
运行完毕后再进入 toa 内置的异常处理流程,最后respond
客户端。如果onerror
返回true
,则会忽略该异常,异常不会进入内置异常处理流程,然后直接respond
客户端。
// with full arguments
const app = new Toa(server, {
onerror: function (error) {}
})
设置 cookie 签名密钥,参考 Keygrip。
注意,签名密钥只在配置项 signed
参数为真时才会生效:
this.cookies.set('name', 'test', {signed: true})
config 会被 context.config
继承,但 context.config
不会修改 app.config
。
app.config = config
app.config 默认值:
{
proxy: false, // 决定了哪些 `proxy header` 参数会被加到信任列表中
env: process.env.NODE_ENV || 'development', // node 执行环境
subdomainOffset: 2,
poweredBy: 'Toa',
secureCookie: null
}
加载中间件,返回 app
,fn
必须是 thunk
函数或 generator
函数,函数中的 this
值为 context
。
app.use(function (callback) {
// task
// this === context
callback(err, result)
})
app.use(function * () {
// task
// this === context
yield result
})
设置 onerror
函数,当 app 捕捉到程序运行期间的错误时,会先使用 options.onerror
(若提供)处理,再使用内置的 onResError
函数处理响应给客户端,最后抛出给 app.onerror
处理,应用通常可以在这里判断错误类型,根据情况将错误写入日志系统。
// default
app.onerror = function (err) {
// ignore null and response error
if (err == null || (err.status && err.status < 500)) return
if (!util.isError(err)) err = new Error('non-error thrown: ' + err)
// catch system error
let msg = err.stack || err.toString()
console.error(msg.replace(/^/gm, ' '))
}
返回 app request listener。
const http = require('http')
const toa = require('toa')
const app = toa()
const server = http.createServer(app.toListener())
server.listen(3000)
等效于:
const toa = require('toa')
const app = toa()
app.listen(3000)
返回 server
,用法与 httpServer.listen
一致。
// 与 httpServer.listen 一致
app.listen(3000)