Koa 介绍

  • Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造,致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。

    • 官网:https://koajs.com/
    • GitHub 仓库:https://github.com/koajs/koa
    • 一个翻译的中文网:https://koa.bootcss.com/
  • Koa 的原理和内部结构很像 Express,但是语法和内部结构进行了升级
  • Koa 内部使用 ES6 编写,号称是下一代 Node.js Web 框架
  • 它的主要特点是通过利用 async 函数,帮你丢弃回调函数
    • Koa 1 是基于 ES2015 中的 Generator 生成器函数结合 CO 模块
    • Koa 2 完全抛弃了 Generator 和 co,升级为了 ES2017 中的 async/await 函数
  • 正是由于 Koa 内部基于最新的异步处理方式,所以使用 Koa 处理异常更加简单
  • Koa 中提供了 context 上下文对象
    • Koa 包装和扩展了 Nodejs 中的 req 和 res
    • Express 只是扩展了 req 和 res
  • Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
    • Koa 本身并不支持路由、模板、发送文件、JSONP 等功能,需要单独安装对应的中间件
  • 有很多开发工具/框架都是基于 Koa 的
    • Egg.js - 企业级 Web 开发框架
    • 构建工具 Vite - Vue 3 构建工具
  • Koa vs Express 官方对比
  • 其他评价
    • koa 2 好用,设计上的确有优势。优势不在能实现更强的功能,而是可以更简单地完成功能。
    • koa 2 社区远不如 express
    • koa 1 在思想上与 koa 2 是一致的,但是 koa 2 的实现更漂亮
  • Awesome Koa - 第三方仓库,收录了一些和 Koa 相关的资源,教程、中间件等

Koa 基本使用

使用 Koa 启动一个 HTTP 服务

npm init -y
# 安装 koa
npm i koa
// app.js
const Koa = require('koa')const app = new Koa()// Koa 没有路由系统,只有中间件功能
// ctx:context 上下文对象,包含请求和响应相关方法
app.use(ctx => {// 发送响应ctx.body = 'Hello Koa'
})app.listen(3000, () => {console.log('server is running on http://localhost:3000')
})
nodemon ./app.js

Koa 中的路由

Koa 本身不自带路由功能,如果想要对不同的请求路径进行分发处理,需要自己手动编码处理。

app.use(ctx => {const path = ctx.pathconsole.log(path);if (path === '/') {ctx.body = 'home page'} else if (path === '/foo') {ctx.body = 'foo page'} else {ctx.body = '404 Not Found.'}
})

实际上 Koa 将一些功能单独封装成 npm 包,其中包括路由功能。

在 Koa.js (github.com) 中搜索 route 仓库可以找到几个官方提供的路由工具包,推荐使用 koajs/router,它使用 Express 风格的方法(app.getapp.post 等),详情参考API 文档。

# 安装
npm i @koa/router
// app.js
const Koa = require('koa')
const Router = require('@koa/router')const app = new Koa()
const router = new Router()router.get('/', ctx => {ctx.body = 'home page'
})router.post('/', ctx => {ctx.body = 'post /'
})router.get('/foo', ctx => {ctx.body = 'foo page'
})router.get('/bar', ctx => {// 重定向ctx.redirect('/foo')
})router.get('/users/:id', ctx => {ctx.body = ctx.params
})app// 挂载路由配置.use(router.routes())// 配置允许的请求方法:OPTIONS 请求的 Allow 请求头.use(router.allowedMethods())app.listen(3000, () => {console.log('server is running on http://localhost:3000')
})

Koa 中的静态资源托管

koajs/static 模块封装了静态资源托管的功能。

npm i koa-static
// app.js
const Koa = require('koa')
const static = require('koa-static')
const path = require('path')const app = new Koa()// http://localhost:3000/css/style.css 访问 /public/css/style.css 文件
app.use(static(path.join(__dirname, './public')))app.listen(3000, () => {console.log('server is running on http://localhost:3000')
})

Koa 的中间件不能通过第一个参数设置请求路径,通过下面的方式给静态资源目录添加虚拟路径会报错:

app.use('/public', static(path.join(__dirname, './public')))

可以使用 Koa 的另一个模块 koajs/mount 将 Koa 应用或中间件装载到指定路径:

npm i koa-mount
// mount(<路径>, <中间件>)
app.use(mount('/public', static(path.join(__dirname, './public'))))

Koa 中间件

中间件执行栈

Koa 最大的特色和 Express 一样,也是完全基于中间件(middleware)构建的 web 框架。

Koa 中间件和 Express 中间件有很大的区别,Koa 中间件完全基于洋葱模型(如图):

  • 多个中间件会形成一个栈结构(middle stack),以“先进后出”(first-in-last-out)的顺序执行。
  • 最外层的中间件首先执行。
  • 调用 next 函数的时候,会把执行权交给下一个中间件
  • 最内层的中间件最后执行
  • 执行结束后,把执行权交回上一层的中间件
  • 最外层的中间件收回执行权后,执行 next 函数后面的代码

下面通过代码查看中间件的栈结构:

const one = (ctx, next) => {console.log('>> one')next()console.log('<< one')
}const two = (ctx, next) => {console.log('>> two')next()console.log('<< two')
}const three = (ctx, next) => {console.log('>> three')next()console.log('<< three')
}app.use(one)
app.use(two)
app.use(three)

打印结果:

>> one
>> two
>> three
<< three
<< two
<< one

如果中间件内部没有调用 next 函数,那么执行权就不会传递下去。例如将 two 函数中的 next() 注释,打印结果:

>> one
>> two
<< two
<< one

异步中间件

迄今为止,所有例子的中间件都是同步的,不包含异步操作。如果有异步操作(比如读取数据库、读取文件),中间件就必须写成 async 函数:

const Koa = require('koa')
const path = require('path')
const fsPromises = require('fs').promisesconst app = new Koa()app.use(async (ctx, next) => {const data = await fsPromises.readFile(path.join(__dirname, './views/index.html'))// 设置 content-type 为 text/html// 或者在读取文件的时候设置编码为 `utf8`ctx.type = 'html'ctx.body = datanext()
})app.listen(3000, () => {console.log('server is running on http://localhost:3000')
})

合并多个中间件

Koa 默认只能一个一个挂载中间件:

app.use(one)
app.use(two)
app.use(three)

可以使用中间件组合工具 koajs/compose,将多个中间件合并成同一个中间件去挂载。

npm i koa-compose
app.use(compose([one, two, three]))

全局异常处理

下面是捕获并手动响应错误的中间件:

app.use(ctx => {try {JSON.parse('string')ctx.body = 'Hello Koa'} catch (error) {ctx.response.status = 500ctx.response.body = '服务端内部错误'}
})

也可以使用 Koa 提供的快捷方法 ctx.throw 来响应错误:

app.use(ctx => {try {JSON.parse('string')ctx.body = 'Hello Koa'} catch (error) {// ctx.response.status = 500// ctx.response.body = '服务端内部错误'// ctx.throw(500) // body => Internal Server Errorctx.throw(404) //  body => Not Found}
})

上例是对单个中间件的错误捕获处理,如果要统一的处理程序中的异常,就要利用洋葱中间件的模型,将捕获错误的代码写在最外层:

const Koa = require('koa')
const app = new Koa()// 最外层添加异常捕获的中间件
app.use((ctx, next) => {try {next()} catch (error) {ctx.response.status = 500ctx.response.body = error.message}
})app.use(ctx => {JSON.parse('string')ctx.body = 'Hello Koa'
})...

可以看到 Koa 处理错误的方式相比 Express 方便一些:不需要在每个中间件中 try-catch 捕获错误并将错误传递给 next

注意上例使用的都是同步中间件,如果是异步中间件就要在 try-catch 中使用 await

// 最外层添加异常捕获的中间件
app.use(async (ctx, next) => {try {// 使用 await 等待下一个中间件处理完成await next()} catch (error) {ctx.response.status = 500ctx.response.body = error.message}
})// 同步中间件:A
app.use((ctx, next) => {next()
})// 异步中间件:B
app.use(async ctx => {// 读取不存在的文件await fsPromises.readFile('file.txt')
})

但是这样不会捕获中间件 B 的错误,因为上层的中间件 A 是同步的,并未等待下层中间件的结果,最外层的错误处理中间件 await 的是中间件 A 的执行结果。

解决办法有:

// 方案一,同步中间件返回下层中间件的执行结果
// 同步中间件:A
app.use((ctx, next) => {return next()
})
// 方案二,将同步中间件改为异步中间件,await next()
// 同步中间件:A
app.use(async (ctx, next) => {await next()
})

这属于 JS 的 Promise 语法问题,与 Koa 和中间件无关。

建议:所有的中间件都使用 asycn 异步函数,使用 await 等待 next()

另一种异步处理方式

除了使用外层中间件的方式捕获错误,Koa 还可以通过监听 error 事件捕获错误:

// 可以在任意位置监听事件
app.on('error', err => {console.log(err)
})

**注意:**使用外层中间件 try-catch 捕获并处理了错误,并不会触发 error 事件。

如果既要在中间件中处理异常,又要触发 error 事件,可以在中间件中手动触发 error 事件:

// 最外层添加异常捕获的中间件
app.use(async (ctx, next) => {try {await next()} catch (error) {ctx.response.status = 500ctx.response.body = error.message// 触发 error 事件ctx.app.emit('error', error, ctx)}
})

实际项目中,使用二者之一即可(建议使用中间件)。

Koa 学习 01 Koa 介绍和基本使用(路由、静态资源托管、中间件)相关推荐

  1. Koa 学习 02 Koa 实现原理和极简模拟案例

    通过模拟一个极简版本的 Koa 学习实现原理. 初始化项目 # 安装 koa npm i koa 添加启动文件: // app.js const Koa = require('koa')const a ...

  2. Gatsby 学习 - 01 Gatsby 介绍、创建页面

    本文 Gatsby 版本为 v3. Gatsby 介绍 Gatsby 是一个基于 React 的静态站点生成器. Gatsby 通过 React 开发应用,当应用开发完成后,Gatsby 可以把这个 ...

  3. Jest 学习01 - Jest 介绍、快速体验、vscode 智能提示、配置、监视模式、Babel 配置

    起步 测试到底测什么 提到测试的时候,即使是最简单的一个代码块可能都让初学者不知所措.最常问的问题的是"我怎么知道要测试什么?".如果你正在写一个 Web 应用,那么依次测试每个页 ...

  4. SpringBoot学习笔记(3):静态资源处理

    SpringBoot学习笔记(3):静态资源处理 在web开发中,静态资源的访问是必不可少的,如:Html.图片.js.css 等资源的访问. Spring Boot 对静态资源访问提供了很好的支持, ...

  5. Koa学习(一)——Koa介绍

    Koa--基于Node.js平台的下一代Web框架. Koa2介绍 1. Koa简介 2. Koa历史版本 3. 应用场景 4. Koa扩展框架 1. Koa简介 Koa 官网 Koa所谓的" ...

  6. vue.js 2.0 官方文档学习笔记 —— 01. vue 介绍

    这是我的vue.js 2.0的学习笔记,采取了将官方文档中的代码集中到一个文件的形式.目的是保存下来,方便自己查阅. !官方文档:https://cn.vuejs.org/v2/guide/ 01. ...

  7. 【对比学习】koa.js、Gin与asp.net core——中间件

    web框架中间件对比 编程语言都有所不同,各个语言解决同一类问题而设计的框架,确有共通之处,毕竟是解决同一类问题,面临的挑战大致相同,比如身份验证,api授权等等,鄙人对node.js,golang, ...

  8. 【学习Koa】原生koa2 静态资源服务器例子

    实现思路 首先读取当前路径下所有的文件和文件夹 当去点击某个列表项时判断其实文件还是文件夹,文件的话直接读取,文件夹则再次利用上一个步骤读取并展示 文件结构 代码 index.js 入口文件 cons ...

  9. html5学习笔记---01.HTML5介绍,02.HTML5的新特性

    2013/6/10 01.HTML5介绍 a.创梦技术qq交流群:CreDream:251572072 -------------------- a.创梦技术qq交流群:CreDream:251572 ...

最新文章

  1. iOS_多线程(一)
  2. SANS:2012年度日志管理调查报告
  3. mysql删除默认密码_修改mysql默认密码方法
  4. 云炬Qtpy5开发与实战笔记 2PyCharm添加QTDesinger扩展并创建第一个.ui文件
  5. Linux常用的25条命令
  6. asp.net页生命周期图解---msdn
  7. LogManager分析
  8. Jetpack 新成员 SplashScreen:为全新的应用启动效果赋能!
  9. Ubuntu 安装 ROS 详细教程
  10. NoSQL数据库简介——《大数据技术原理与应用》课程学习总结
  11. PHP 每小时抽奖,项目3:PHP抽奖程序 ,抽奖规则代码 分时间段
  12. Spring Boot入门教程(三十六):支付宝集成-当面付
  13. Java户籍管理系统的设计与实现
  14. django管理后台列表页,TextField字段展示换行等格式(format_html)
  15. Flex中实现double-click修改DataGrid
  16. 2021-05-16 C#.NET面试题 列举你知道的数字格式化转换
  17. 揭秘新推广渠道::利用腾讯文档做QQ消息弹窗
  18. ORB-SLAM3运行时出现“段错误(核心已转储)”解决方案
  19. 公钥,密钥原理学习(数学之美)
  20. 在SAP中使用标准表维护SM30说明

热门文章

  1. 虚拟同步发电机预同步(无缝切换)matlab/simulink仿真模型
  2. 23种设计模式之外观模式
  3. sae微信公众平台php,SAE 上使用PHP搭建微信公众号后台
  4. 入门版:正则表达式教程
  5. python刷网易云_利用Python获取网易云音乐数据,python
  6. 类型转换(自动转换,强制转换)
  7. [附源码]JAVA+ssm基于微信的基层党建信息系统(程序+Lw)
  8. CG行业云渲染服务的演进之路
  9. LR9系列安装报错解决(Setup has determined that a previous installation has not completed.)
  10. ubuntu 的 document viewer evince 发生 Could not open X display 错误的处理