koa简介
初试koa,看了下官网介绍,记录一下学习心得。
koa是致力于成为一个更小、更健壮、更富有表现力的 Web 框架。跟express相比,最核心的部分就是用新的async function 解决了回调函数的噩梦。
比如用express实现一个计算程序处理时间的功能,用express写法,代码如下:
|
|
express的中间件形式,需要每个中间件手动调用next函数,把执行权限移交到下一个注册的中间件。
如果用koa来写,代码如下:
|
|
相对而言,代码简单了很多。想要学习koa,先要学习一下基础知识点,async函数。
koa的代码级联
代码级联是通过async函数实现的(Koa v2.x 移除了内置的 Generator 支持,使用 async 函数替代),先简单介绍下async函数,语法很简单:
|
|
async函数返回一个promise对象,所以可以使用then方法添加回调函数。当函数体执行的时候,遇到await的时候,会执行后面的表达式,表达式可以是原始值类型或者返回Promise对象。如果是个异步表达式的话,javascript会中断本次执行,执行其他内容。等异步执行结束,会返回到上次中断的地方,继续往下执行。
比如,我想中断两秒钟,返回一个hello world!。代码如下:
|
|
当执行的时候,result并不会立即返回,而是等待2秒,然后返回。
用async函数有什么好处?
- 代码结构清晰,执行过程明了,避免了回调嵌套的代码
- 函数的作用域得以保存,不再用callback( data ) 函数传参
- 易于错误的捕获
第三点,怎么错误捕获?平常如果异步回调函数执行的时候,一般都是在callback中,捕获错误 , 因为当执行异步操作的时候,异步函数代码执行完毕,javascript执行其他内容的时候,函数的资源会被垃圾回收,等事件机制通知回调函数的时候,原来的资源早已不在,所以如果发生错误,也是只能通过函数传参。如下:
|
|
而使用async函数,因为函数只是暂停执行,里面的变量并不会被回收,所以可以继续使用。
koa利用了async的特性,让嵌套中间件执行之后,不用通过绑定全局变量,或者在request对象
上绑定属性来传参了,直接在函数体里面用之前定义的变量,方便了很多。koa的async调用机制的介绍完毕,下面是一些常用api的说明。
Koa配置
koa的应用程序配置默认在app实例上,目前支持
- app.env 默认为
NODE_ENV
,如果没有配置的话,为"development"
- app.proxy 当设置为true时,支持 X-Forwarded-Host
- app.subdomainOffset 子域名偏移量,属性默认为2,如域名“tobi.ferrets.example.com” 执行:ctx.subdomains 返回[“ferrets”, “tobi”],如果app.subdomainOffset设为3,则返回[“tobi”]。
app.listen( … )监听端口
|
|
还是使用了node内置的http模块
app.callback()
执行这个函数返回的函数可以用于处理http.createServer()
的请求,也可以用这个回调函数将你的koa应用挂载在express或者Connect应用中。
app.use(middleWare)
koa中这个方法很常用了,将给定的middleWare当作中间件加载到应用中。middleWare
接受两个参数ctx
和next
,第一个参数是上下文,第二个参数是执行下一个中间件的回调。
app.context
app.context
是middleWare第一个参数ctx实例的原型。想要给ctx添加属性,可以直接编辑app.context。对于在应用程序中经常使用的属性或者函数,这个api非常有用。不过不建议过度依赖,毕竟类似全局变量,而全局变量是evil的😈。官网给的例子,比如数据库实例可以挂在到ctx上。
|
|
错误处理
默认所有的错误都通过stderr
输出,如果设置了app.silent
为true的话,就不输出。当err.status是404或者err.expose等于true,则默认不输出。如果想自定义错误处理逻辑, 可以定义一个「错误事件」来监听 Koa app 中发生的错误:
|
|
当 req/res 周期中出现任何错误且无法响应客户端时,Koa 会把 Context
(上下文) 实例作为第二个参数传递给 error 事件。当错误发生时,如果还没有数据返回客户端,koa会响应500 内部错误给客户端,并且会触发app-level的error
事件,可以用来记录日志。
Context
一个koa的Context封装了node原生的request和response对象,提供了一些方便的API供应用程序开发。
随着每个request请求,都会创建一个新的Context,当中间件被调用时,它会被会传到给每个中间件的第一个参数中。
|
|
ctx中的很多访问器和方法,简单代理了ctx.request或者ctx.resposne ,因为有些高频API,直接代理了方便使用。比如ctx.type
和ctx.length
代理了response对象,ctx.path
和ctx.method
代理了request对象。
ctx.req node的request对象
ctx.res node的resposne对象
避开koa,而直接操作node底层的response对象要避免。比如
- res.statusCode
- res.writeHead()
- res.write()
- res.end()
ctx.request koa的request对象
cox.response koa的response对象
ctx.state koa推荐挂载数据的地方,比如用户信息
1ctx.state.user = await User.find(id) ;ctx.app 应用程序实例
cox.throw 自定义状态码响应的方法。比如
1234ctx.throw(403);ctx.throw('name required', 400);ctx.throw(400, 'name required');ctx.throw('something exploded');cox.respond 如不想使用koa内置的response处理方法,可以设置this.respond=false,跳过koa针对response的预处理,你可以自己设置response对象。算是一种hack方法吧,一般不常用
……
Request
简单介绍一下koa的request对象,一些常用的API
- request.header 请求头
- request.method 请求方法
- request.length 请求头的Context-Length
- request.originalUrl 获取request的originalUrl
- request.origin origin URL,包括,protocol和host
- request.path 请求路径
- request.querystring 查询参数 , 不包括?
- request.search 原始的query string,包括?
- request.query 结构化了的查询参数
….
Response
简单介绍一下koa的response对象,一些常用的API
- response.header 响应对象
- response.status 响应状态,默认无值
- response.message 响应消息,一般和状态码一起设置
- response.length 设置响应的大小
- response.body 返回响应内容
- response.get(field) 获取响应的头部字段
- response.set(field,value) 设置响应头的内容
- response.append(field,value) 追加额外的头部字段内容
- response.redirect( url , [alt] ) 重定向,可以自定’back’,能提供Referrer支持,没有时,可用alt指定
- response.lastModified 如果响应头部包含Last-Modified,则用Date对象返回
…..
具体API可以查看本文后面的官网链接。
最后介绍一个debug模块的使用
通常我们开发环境需要使用console来打印调试一些内容,但是生产环境又不需要这些内容,可以使用debug模块,debug模块可以对log进行分组,而且只有设置了DEBUG的情况下,才会输出内容。
|
|
接下来在代码中引入
|
|
接下来就可以启动了:
|
|
参考文档: