# Koa

# 基础知识

# 简介

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

# 安装

yarn add koa
1

# 应用程序

Koa 应用程序是一个包含一组中间件函数的对象,它是按照类似堆栈的方式组织和执行的。Koa 类似你可能遇到过的许多其他中间件系统,例如 Ruby 的 Rack,Connect 等,然而,一个关键的设计点是在其低级中间件层提供高级“语法糖”。这提高了互操作性,稳定性,并使书写中间件更加愉快。

这包括诸如内容协商,缓存清理,代理支持和重定向等常见任务的方法。尽管提供了相当多的有用的方法 Koa 仍保持来一个很小的体积,因为没有捆绑中间件。

必修的 hello world 应用:

const Koa = require('koa');
const app = new Koa();

app.use(async ctx => {
  ctx.body = 'Hello World'; 
});

app.listen(3000, () => {
  console.log("listen: 3000")
});
1
2
3
4
5
6
7
8
9
10
declare class Application<
    StateT = Application.DefaultState,
    CustomT = Application.DefaultContext
> extends EventEmitter {
    proxy: boolean;
    middleware: Application.Middleware<StateT, CustomT>[];
    subdomainOffset: number;
    env: string;
    context: Application.BaseContext & CustomT;
    request: Application.BaseRequest;
    response: Application.BaseResponse;
    silent: boolean;
    keys: Keygrip | string[];

    constructor();

    /**
     * Shorthand for:
     *
     *    http.createServer(app.callback()).listen(...)
     */
    listen(
        port?: number,
        hostname?: string,
        backlog?: number,
        listeningListener?: () => void,
    ): Server;
    listen(
        port: number,
        hostname?: string,
        listeningListener?: () => void,
    ): Server;
    listen(
        port: number,
        backlog?: number,
        listeningListener?: () => void,
    ): Server;
    listen(port: number, listeningListener?: () => void): Server;
    listen(
        path: string,
        backlog?: number,
        listeningListener?: () => void,
    ): Server;
    listen(path: string, listeningListener?: () => void): Server;
    listen(options: ListenOptions, listeningListener?: () => void): Server;
    listen(
        handle: any,
        backlog?: number,
        listeningListener?: () => void,
    ): Server;
    listen(handle: any, listeningListener?: () => void): Server;

    /**
     * Return JSON representation.
     * We only bother showing settings.
     */
    inspect(): any;

    /**
     * Return JSON representation.
     * We only bother showing settings.
     */
    toJSON(): any;

    /**
     * Use the given middleware `fn`.
     *
     * Old-style middleware will be converted.
     */
    use<NewStateT = {}, NewCustomT = {}>(
        middleware: Application.Middleware<StateT & NewStateT, CustomT & NewCustomT>,
    ): Application<StateT & NewStateT, CustomT & NewCustomT>;

    /**
     * Return a request handler callback
     * for node's native http/http2 server.
     */
    callback(): (req: IncomingMessage | Http2ServerRequest, res: ServerResponse | Http2ServerResponse) => void;

    /**
     * Initialize a new context.
     *
     * @api private
     */
    createContext<StateT = Application.DefaultState>(
        req: IncomingMessage,
        res: ServerResponse,
    ): Application.ParameterizedContext<StateT>;

    /**
     * Default error handler.
     *
     * @api private
     */
    onerror(err: Error): void;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

# 级联

Koa 中间件以更传统的方式级联,你可能习惯使用类似的工具-之前难以让用户友好地使用 node 的回调。然而,使用 async 功能,我们可以实现“真实”的中间件。对比 Connect 的实现,通过一系列功能直接传递控制,直到一个返回,Koa 调用“下游”,然后控制流回“上游”

下面以 “Hello world” 的响应作为示例,当请求开始时首先请求流通过 x-response-time 和 loggin 中间件,然后继续移交控制给 response 中间件。当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。

const Koa = require('koa');
const app = new Koa();

// logger
app.use(async (ctx, next) => {
  // console.log(ctx, next);
  await next(); // 等待下一个中间件完成
  const rt = ctx.response.get("X-Response-Time");
  console.log(`${ctx.method} ${ctx.url} - ${rt}`)
})

// x-response-time
app.use(async (ctx, next) => {
  const start = Date.now();
  await next(); // 等待下一个中间件完成
  const ms = Date.now() - start;
  ctx.set("X-Response-Time", `${ms}ms`);
})

app.use(async ctx => {
  ctx.body = 'Hello World'; // 调用玩该中间件后,开始调用 logger 、x-resonse-time 后半部分
});

app.listen(3000, () => {
  console.log("listen: 3000")
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# app.listen(...)

Koa 应用程序不是 HTTP 服务器的 1 对 1 展现。可以将一个或多个 Koa 应用程序安装在一起形成具有单个 HTTP 服务器的更大应用程序。

创建并返回 HTTP 服务器,将给定的参数传递给 Server#listen()。这些内容都记录在 node.org

以下是一个无作用的 Koa 应用程序被绑定到 3000 端口:

const Koa = require('koa');
const app = new Koa();
app.listen(3000);
1
2
3

这里的 app.listen(...) 方法只是以下方法的语法糖:

const http = require('http');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
1
2
3
4

这意味着你可以将同一个应用程序同时作为 HTTP 和 HTTPS 或多个地址:

const http = require('http');
const https = require('https');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
https.createServer(app.callback()).listen(3001);
1
2
3
4
5
6

# app.use(function)

将给定的中间件方法添加到此应用程序。中间件组件是一个函数,它拦截 HTTP 服务器提供的请求和响应对象,执行逻辑,然后或者结束响应,或者把它传递给下一饿中间件组件。app 用分派器把中间件“连接”在一起。

# 上下文(Context)

Koa Context 将 node 的 request 和 response 对象封装到单个对象中,为编写 Web 应用程序和 API 提供了许多有用的方法。这些操作在 HTTP 服务器开发中频繁使用,它们被添加到此级别而不是更高级别的框架,这将强制中间件重现实现此通用功能。

# 进阶活用

# 底层源流

# 参考资料

Last Updated: 2/25/2020, 3:09:30 PM