Koa 入门

by koa · 2020年7月7日4:24 · 98 WORDS  ·  ~ 1 mins reading time · 0  Visitors | 

KOA 中文文档

KOA 是由 Express 原班人马打造的新 Web 框架.

Hello World

yarn add koa

then

var koa = require('koa');
var app = new koa();
app.use(async ctx => {
ctx.body='Hello, World';
})
app.listen(3000);

07141451

应用程序

级联

const Koa = require('koa');
const app = new Koa();
// logger
app.use(async (ctx, next) => {
console.log('func1 start');
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
console.log('func1 end');
});
// x-response-time
app.use(async (ctx, next) => {
console.log('func2 start');
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
console.log('func2 end');
});
// response
app.use(async ctx => {
console.log('func3 start');
ctx.body = 'Hello World';
console.log('func3 end');
});
app.listen(3000);
~/Desktop/lkoa ❯ node "/Users/admin/Desktop/lkoa/main.js" ✘ INT 3m 11s 14:39:01
func1 start
func2 start
func3 start
func3 end
func2 end
GET /44 - 2ms
func1 end

KOA 1 时代是用 Generate 函数来做的, 到二代改了, 这差不多相当于 yield 的影子吧.

遇到 next() 实际上是先跳至下一个 use, 之后再跳回来 (有 await). 如果把第一个 await 去掉, 结果会是下面这样(异步):

~/Desktop/lkoa ❯ node "/Users/admin/Desktop/lkoa/main.js" ✘ INT 3m 59s 14:43:38
func1 start
func2 start
func3 start
func3 end
GET /44 -
func1 end
func2 end

设置

应用程序设置是 app 实例上的属性, 官方文档给了几个设置的例子:

  • app.env 默认是 NODE_ENV 或 "development"
  • app.keys 签名的 cookie 密钥数组
  • app.proxy 当真正的代理头字段将被信任时
  • 忽略 .subdomains 的 app.subdomainOffset 偏移量,默认为 2
  • app.proxyIpHeader 代理 ip 消息头, 默认为 X-Forwarded-For
  • app.maxIpsCount 从代理 ip 消息头读取的最大 ips, 默认为 0 (代表无限)

这有个例子:

app.use(async ctx => {
ctx.body = `app.env: ${app.env}
app.keys: ${app.keys}
app.proxy: ${app.proxy}
app.subscriptions: ${app.subscriptions}
app.proxyIpHeader: ${app.proxyIpHeader}
app.maxIpCount: ${app.maxIpCount}
`});

结果如下:

07152111

修改设置有两种方式, 一种是构造时修改:

const Koa = require('koa');
const app = new Koa({ proxy: true });

另一种是动态修改:

const Koa = require('koa');
const app = new Koa();
app.proxy = true;

app.listen(...)

语法糖:

app.listen(3000);
// 等同于
http.createServer(app.callback()).listen(3000);

因此可以同时监听多个端口. 同样, app.callback() 也可以挂载到 Connect/Express 中.

app.use(function)

支持链式调用. 如下:

app.use(someMiddleware)
.use(someOtherMiddleware)
.listen(3000)

app.context

是 ctx 的原型, 如下例子所示:

app.context.db = 'this is db';
app.use(async ctx => {
ctx.body = `db: ${ctx.db}`
});

07154441

错误处理

app.on('error', (err, ctx) => {
log.error('server error', err, ctx)
});

上下文 Context

这部分见官方文档

这是一个 ctx 的例子

{
"request": {
"method": "GET",
"url": "/44",
"header": {
"host": "localhost:3000",
"connection": "keep-alive",
"cache-control": "max-age=0",
"dnt": "1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"sec-fetch-site": "none",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"accept-encoding": "gzip, deflate, br",
"accept-language": "zh,en;q=0.9,zh-CN;q=0.8",
"cookie": "xxxxxxxxxxxxxxxxx"
}
},
"response": {
"status": 404,
"message": "Not Found",
"header": {}
},
"app": {
"subdomainOffset": 2,
"proxy": false,
"env": "development"
},
"originalUrl": "/44",
"req": "<original node req>",
"res": "<original node res>",
"socket": "<original node socket>"
}

历史记录

VersionActionTime
1.0Init2020-07-07 12:24
随便写写 © 2022 acdzh