コアの紹介
- Koa は、Express の開発者と同じ人によって構築された新しい Web フレームワークで、Web アプリケーションおよび API 開発のための、より小さく、より表現力豊かで、より堅牢な構成要素となることを目指しています。
- 公式サイト:https://koajs.com/
- GitHub リポジトリ: https://github.com/koajs/koa
- 中国語に翻訳された Web サイト: https://koa.bootcss.com/
- Koa の原理と内部構造は Express とよく似ていますが、構文と内部構造はアップグレードされています
- Koaは内部的に ES6 で書かれており、次世代の Node.js Web フレームワークであると主張しています。
- その主な機能は、非同期関数を使用してコールバック関数を破棄できるようにすることです。
- Koa 1 は、ES2015 の Generator ジェネレーター機能と CO モジュールを組み合わせたものに基づいています。
- Koa 2 は Generator などを完全に放棄し、ES2017 で async/await 機能にアップグレードします
- Koa は最新の非同期処理方式に基づいているため、例外処理に Koa を使用する方が簡単です
- コンテキスト オブジェクトは Koa で提供されます
- Koa は Nodejs で req と res をラップして拡張します
- Express は req と res を拡張するだけです
- Koa はミドルウェアをバンドルしていませんが、サーバーサイド アプリケーションを迅速かつ楽しく作成できる一連のエレガントなメソッドを提供します。
- Koa 自体はルーティング、テンプレート、ファイル送信、JSONP などの機能をサポートしていないため、対応するミドルウェアを別途インストールする必要があります
- Koa に基づいた開発ツール/フレームワークが多数あります
- Koaと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.path
console.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)のウェアハウスを検索すると、いくつかの公式ルーティング ツールキットが見つかります。Expressスタイルのメソッド ( など) を使用するkoajs /routerroute
を使用することをお勧めします。詳細については、API ドキュメントを参照してください。app.get
app.post
# 安装
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 と同様に、完全にミドルウェア上に構築された Web フレームワークです。
Koa ミドルウェアと Express ミドルウェアには大きな違いがあり、Koa ミドルウェアは完全にオニオン モデルに基づいています (図に示すように)。
- 複数のミドルウェアはスタック構造(ミドルスタック)を形成し、「先入れ後出し」の順序で実行されます。
- 最も外側のミドルウェアが最初に実行されます。
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
非同期ミドルウェア
これまでのミドルウェアの例はすべて同期であり、非同期操作は含まれていません。非同期操作 (データベースの読み取り、ファイルの読み取りなど) がある場合は、ミドルウェアを非同期関数として記述する必要があります。
const Koa = require('koa')
const path = require('path')
const fsPromises = require('fs').promises
const 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 = data
next()
})
app.listen(3000, () => {
console.log('server is running on http://localhost:3000')
})
複数のミドルウェアを組み合わせる
デフォルトでは、Koa はミドルウェアを 1 つずつしかマウントできません。
app.use(one)
app.use(two)
app.use(three)
ミドルウェア結合ツールkoajs/composeを使用すると、複数のミドルウェアを1つのミドルウェアに結合してマウントできます。
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 = 500
ctx.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 Error
ctx.throw(404) // body => Not Found
}
})
上記の例は、単一のミドルウェアのエラー キャプチャ プロセスです。プログラム内で例外を均一に処理したい場合は、オニオン ミドルウェア モデルを使用して、最外層でエラーをキャッチするコードを記述する必要があります。
const Koa = require('koa')
const app = new Koa()
// 最外层添加异常捕获的中间件
app.use((ctx, next) => {
try {
next()
} catch (error) {
ctx.response.status = 500
ctx.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 = 500
ctx.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 やミドルウェアとは関係ありません。
提案: すべてのミドルウェアに async 関数を使用しasycn
、await
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 = 500
ctx.response.body = error.message
// 触发 error 事件
ctx.app.emit('error', error, ctx)
}
})
実際のプロジェクトではどちらでも使えます(ミドルウェア推奨)。