Koa翻译文档

192 阅读19分钟

打开koa中文网站发现域名备案出了点问题,花了一下午时间翻译了一份中文手册。如有啥不对的地方还请各位大佬指出。

翻译时间:2022年10月11日

官网地址:koajs.com/

Introduction

Koa 是由 Express 背后的团队设计的新 Web 框架,旨在为 Web 应用程序和 API 提供更小、更具表现力和更强大的基础。通过利用异步函数,Koa 允许您放弃回调并大大增加错误处理能力。Koa 没有在其核心中捆绑任何中间件,它提供了一套优雅的方法,使编写服务器变得快速而愉快。

Installation

ps: node版本需大于7.6.0

$ nvm install 7
$ npm i koa -S
$ node my-koa-app.js

Application

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);

Cascading

Koa 中间件以更传统的方式级联,你可能习惯于使用类似的工具——这在以前很难通过节点使用回调使用户友好。然而,通过异步函数,我们可以实现“真正的”中间件。对比 Connect 的实现,它简单地通过一系列函数传递控制直到一个返回,Koa 调用“下游”,然后控制流回到“上游”。

以下示例以“Hello World”响应,但首先请求流经 x-response-time 和日志中间件以标记请求何时开始,然后通过响应中间件产生控制权。当中间件调用 next() 时,函数会挂起并将控制权传递给定义的下一个中间件。在没有更多的中间件在下游执行之后,堆栈将展开,每个中间件都恢复执行其上游行为。

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

// logger

app.use(async (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`);
});

// response

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

app.listen(3000);

Settings

应用程序配置是应用程序实例上的属性,目前支持以下内容:

  • app.env 默认为 NODE_ENV 或“development”
  • app.keys 签名的 cookie 密钥数组
  • app.proxy 当真正的代理标头字段将被信任时
  • app.subdomainOffset 要忽略的 .subdomains 偏移量,默认为 2
  • app.proxyIpHeader 代理ip头,默认为X-Forwarded-For
  • app.maxIpsCount 从代理ip头读取的最大ips,默认为0(表示无穷大)
const Koa = require('koa');
// 通过构造函数
const app = new Koa({ proxy: true });
// 动态设置
app.env = 'development'

app.listen(...)

Koa 应用程序不是 HTTP 服务器的一对一表示。可以将一个或多个 Koa 应用程序安装在一起,以使用单个 HTTP 服务器形成更大的应用程序。

创建并返回一个 HTTP 服务器,将给定的参数传递给 Server#listen()。这些参数记录在 nodejs.org 上。下面是一个绑定到 3000 端口的无用 Koa 应用:

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

app.listen(...) 方法只是以下内容的糖:

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

这意味着您可以启动与 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);

app.callback()

返回适合 http.createServer() 方法处理请求的回调函数。你也可以使用这个回调函数在 Connect/Express 应用中挂载你的 Koa 应用。

app.use(function)

将给定的中间件函数添加到此应用程序。 app.use() 返回this,所以是可链接的。

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

等同于:

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

有关详细信息,请参阅中间件

app.keys=

设置签名的 cookie 密钥。

这些被传递给 KeyGrip,但是您也可以传递您自己的 KeyGrip 实例。例如以下是可以接受的:

app.keys = ['OEK5zjaAMPc3L6iK7PyUjCOziUH3rsrMKB9u8H07La1SkfwtuBoDnHaaPCkG5Brg', 'MNKeIebviQnCPo38ufHcSfw3FFv8EtnAe1xE02xkN1wkCV1B2z126U44yk2BQVK7'];
app.keys = new KeyGrip(['OEK5zjaAMPc3L6iK7PyUjCOziUH3rsrMKB9u8H07La1SkfwtuBoDnHaaPCkG5Brg', 'MNKeIebviQnCPo38ufHcSfw3FFv8EtnAe1xE02xkN1wkCV1B2z126U44yk2BQVK7'], 'sha256');

出于安全原因,请确保密钥足够长且随机。

在使用 { signed: true } 选项签署 cookie 时,这些密钥可以被轮换和使用:

ctx.cookies.set('name', 'tobi', { signed: true });

app.context

app.context 是创建 ctx 的原型。您可以通过编辑 app.context 向 ctx 添加其他属性。这对于向 ctx 添加要在整个应用程序中使用的属性或方法很有用,这可能会更高效(无中间件)和/或更容易(更少的 require()),但代价是更多地依赖 ctx,这可能是被认为是反模式。

例如,要从 ctx 添加对数据库的引用:

app.context.db = db();

app.use(async ctx => {
  console.log(ctx.db);
});

ps:

  • ctx 上的许多属性是使用 getter、setter 和 Object.defineProperty() 定义的。您只能通过在 app.context 上使用 Object.defineProperty() 来编辑这些属性(不推荐)。请参阅 https://github.com/koajs/koa/issues/652
  • 已挂载的应用程序当前使用其父级的 ctx 和设置。因此,挂载的应用程序实际上只是一组中间件。

Error Handling

默认情况下,除非 app.silent 为 true,否则将所有错误输出到 stderr。当 err.status 为 404 或 err.expose 为 true 时,默认错误处理程序也不会输出错误。要执行自定义错误处理逻辑,例如集中式日志记录,您可以添加一个“错误”事件侦听器:

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

如果req/res周期出错,无法响应客户端,也传递Context实例:

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

当发生错误并且仍然可以响应客户端时,即没有数据写入套接字时,Koa 将适当地响应 500“内部服务器错误”。在任何一种情况下,都会发出应用级别的“错误”以用于日志记录。

Context

Koa 上下文将节点的请求和响应对象封装到一个对象中,该对象为编写 Web 应用程序和 API 提供了许多有用的方法。这些操作在 HTTP 服务器开发中使用如此频繁,以至于它们被添加到此级别而不是更高级别的框架中,这将迫使中间件重新实现此通用功能。

每个请求都会创建一个上下文,并在中间件中作为接收者或 ctx 标识符引用,如下面的代码片段所示:

app.use(async ctx => {
  ctx; // is the Context
  ctx.request; // is a Koa Request
  ctx.response; // is a Koa Response
});

为方便起见,许多上下文的访问器和方法只是委托给它们的 ctx.request 或 ctx.response 等效项,并且在其他方面是相同的。[例如 ctx.type 和 ctx.length 委托给response对象,而 ctx.path 和 ctx.method 委托给request。

API

上下文特定的方法和访问器。

ctx.req

Node的request对象

ctx.res

Node的response对象

不支持绕过 Koa 的响应处理。避免使用以下节点属性:

  • res.statusCode
  • res.writeHead()
  • res.write()
  • res.end()

ctx.request

Koa的Request对象

ctx.response

Koa的Response对象

ctx.state

用于通过中间件和前端视图传递信息的推荐命名空间。

ctx.state.user = await User.find(id);

ctx.app

app实例引用

ctx.app.emit

Koa 应用程序扩展了一个内部 EventEmitter。 ctx.app.emit 发出一个类型由第一个参数定义的事件。对于每个事件,您可以连接“侦听器”,这是一个在事件发出时调用的函数。有关更多信息,请参阅错误处理文档。

ctx.cookies.get(name, [options])

使用选项获取 cookie 名称:

  • signed 请求的 cookie 应该被签名

Koa 使用简单地传递选项的 cookies 模块。

ctx.cookies.set(name, value, [options])

使用选项将 cookie 名称设置为值:

  • maxAge:一个数字,表示从 Date.now() 到到期的毫秒数。

  • expires:一个 Date 对象,指示 cookie 的到期日期(默认在会话结束时到期)。

  • path:表示cookie路径的字符串(默认为/)。

  • domain:表示cookie域的字符串(无默认值)。

  • secure:一个布尔值,指示 cookie 是否仅通过 HTTPS 发送(HTTP 默认为 false,HTTPS 默认为 true)。

  • httpOnly:一个布尔值,指示 cookie 是否仅通过 HTTP(S) 发送,而不提供给客户端 JavaScript(默认为 true)。

  • sameSite:一个布尔值或字符串,指示 cookie 是否为“相同站点”cookie(默认为 false)。这可以设置为“strict”、“lax”、“none”或 true(映射到“strict”)。]

  • signed:一个布尔值,指示是否要对 cookie 进行签名(默认为 false)。如果为true,还将发送另一个带有 .sig 后缀的同名 cookie,其 27 字节的 url-safe base64 SHA1 值表示 cookie-name=cookie-value 与第一个 Keygrip 键的哈希值。

  • overwrite:一个布尔值,指示是否覆盖以前设置的同名cookie(默认为false)。如果为true,那么在设置此 cookie 时,在同一请求期间设置的所有具有相同名称(无论路径或域)的 cookie 都会从 Set-Cookie 标头中过滤掉。

Koa 使用简单地传递选项的 cookies 模块。

ctx.throw([status], [msg], [properties])

使用默认为 500 的 .status 属性引发错误的辅助方法,这将允许 Koa 做出适当的响应。允许以下组合:

ctx.throw(400);
ctx.throw(400, 'name required');
ctx.throw(400, 'name required', { user: user });

例如 ctx.throw(400, 'name required') 等价于:

const err = new Error('name required');
err.status = 400;
err.expose = true;
throw err;

请注意,这些是用户级错误,并用 err.expose 标记,这意味着这些消息适用于客户端响应,而错误消息通常不是这种情况,因为您不想泄露故障详细信息。

您可以选择传递一个属性对象,该对象按原样合并到错误中,用于修饰向上游请求者报告的机器友好错误。

ctx.throw(401, 'access_denied', { user: user });

Koa 使用 http-errors 来创建错误。 status 只能作为第一个参数传递。

ctx.assert(value, [status], [msg], [properties])

当 !value 时抛出类似于 ctx.throw() 的错误的辅助方法。 类似于节点的 assert() 方法。

ctx.assert(ctx.state.user, 401, 'User not found. Please login!');

Koa 使用 http-assert 进行断言。

ctx.respond

要绕过 Koa 的内置响应处理,您可以显式设置 ctx.respond = false;。如果您想写入原始 res 对象而不是让 Koa 为您处理响应,请使用此选项。

请注意,Koa 不支持使用它。这可能会破坏 Koa 中间件和 Koa 本身的预期功能。使用这个属性被认为是一种 hack,只是对那些希望在 Koa 中使用传统 fn(req, res) 函数和中间件的人来说是一种便利。

Request aliases

The following accessors and alias Request equivalents:

  • ctx.header
  • ctx.headers
  • ctx.method
  • ctx.method=
  • ctx.url
  • ctx.url=
  • ctx.originalUrl
  • ctx.origin
  • ctx.href
  • ctx.path
  • ctx.path=
  • ctx.query
  • ctx.query=
  • ctx.querystring
  • ctx.querystring=
  • ctx.host
  • ctx.hostname
  • ctx.fresh
  • ctx.stale
  • ctx.socket
  • ctx.protocol
  • ctx.secure
  • ctx.ip
  • ctx.ips
  • ctx.subdomains
  • ctx.is()
  • ctx.accepts()
  • ctx.acceptsEncodings()
  • ctx.acceptsCharsets()
  • ctx.acceptsLanguages()
  • ctx.get()

Response aliases

The following accessors and alias Response equivalents:

  • ctx.body
  • ctx.body=
  • ctx.status
  • ctx.status=
  • ctx.message
  • ctx.message=
  • ctx.length=
  • ctx.length
  • ctx.type=
  • ctx.type
  • ctx.headerSent
  • ctx.redirect()
  • ctx.attachment()
  • ctx.set()
  • ctx.append()
  • ctx.remove()
  • ctx.lastModified=
  • ctx.etag=

Request

Koa Request 对象是 node 的 vanilla request 对象之上的抽象,提供了对日常 HTTP 服务器开发有用的附加功能。

API

request.header

请求头对象。这与节点的 http.IncomingMessage 上的 headers 字段相同。

request.header=

设置请求头对象。

request.headers

请求头对象。别名为 request.header。

request.headers=

设置请求头对象。别名为 request.headers。

request.method

请求方法

request.method=

设置请求方法,对于实现methodOverride()等中间件很有用。

request.length

如果存在或未定义,则将请求 Content-Length 作为数字返回。

request.url

Get request URL.

request.url=

设置请求 URL,对 url 重写很有用。

request.originalUrl

获取请求原始 URL

request.origin

获取 URL 的来源,包括协议(protocol)和主机(host)。e.g.:http://example.com

request.href

获取完整的请求 URL,包括协议、主机和 url。e.g.:http://example.com/foo/bar?q=1

request.path

获取请求路径名。

request.path=

设置请求路径名并在存在时保留查询字符串。

request.querystring

获取没有 ? 的原始查询字符串。

request.querystring=

设置原始查询字符串。

request.search

获取带 ? 的原始查询字符串。

request.host

存在时获取主机(主机名:端口)。当 app.proxy 为 true 时支持 X-Forwarded-Host,否则使用 Host。

request.hostname

存在时获取主机名。当 app.proxy 为 true 时支持 X-Forwarded-Host,否则使用 Host。如果主机是 IPv6,Koa 将解析委托给 WHATWG URL API,注意这可能会影响性能。

request.URL

获取 WHATWG 解析的 URL 对象。

request.type

获取请求 Content-Type 没有“charset”等参数。e.g.:"image/png"

request.charset

在存在时获取请求字符集否则就是undefined。e.g.:"utf-8"

request.query

请注意,此 getter 不支持嵌套解析。e.g.:如果 querystring是"color=blue&size=small" 将会返回 { color: 'blue', size: 'small' }

request.query=

将查询字符串设置为给定对象。请注意,此设置器不支持嵌套对象。e.g.: ctx.query = { next: '/login' };

request.fresh

检查请求缓存是否“新鲜”,也就是内容没有改变。此方法用于 If-None-Match / ETag 和 If-Modified-Since 和 Last-Modified 之间的缓存协商。应在设置一个或多个这些响应标头后引用它。e.g.

// freshness check requires status 20x or 304
ctx.status = 200;
ctx.set('ETag', '123');

// cache is ok
if (ctx.fresh) {
  ctx.status = 304;
  return;
}

// cache is stale
// fetch new data
ctx.body = await db.find('something');

request.stale

与request.fresh相反

request.protocol

返回请求协议,“https”或“http”。当 app.proxy 为 true 时支持 X-Forwarded-Proto。

request.secure

ctx.protocol == 'https' 的简写,用于检查请求是否通过 TLS 发出。

request.ip

请求远程地址。当 app.proxy 为 true 时支持 X-Forwarded-For。

request.ips

当存在 X-Forwarded-For 并启用 app.proxy 时,将返回这些 ips 的数组,从上游 -> 下游排序。禁用时返回一个空数组。

例如,如果值为“client, proxy1, proxy2”,您将收到数组 ['client', 'proxy1', 'proxy2']。

大部分反向代理(nginx)通过proxy_add_x_forwarded_for设置x-forwarded-for,存在一定的安全风险。恶意攻击者可以通过伪造 X-Forwarded-Forrequest 标头来伪造客户端的 IP 地址。客户端发送的请求具有“伪造”的 X-Forwarded-For 请求标头。被反向代理转发后,request.ips 将是 ['forged', 'client', 'proxy1', 'proxy2']。

Koa 提供了两个选项来避免被绕过。

如果可以控制反向代理,可以通过调整配置避免绕过,或者使用koa提供的app.proxyIpHeader,避免读取x-forwarded-for获取ips。

  const app = new Koa({
    proxy: true,
    proxyIpHeader: 'X-Real-IP',
  });

如果你确切知道服务器前面有多少个反向代理,你可以通过配置 app.maxIpsCount 来避免读取用户的伪造请求头:

  const app = new Koa({
    proxy: true,
    maxIpsCount: 1, // only one proxy in front of the server
  });

  // request.header['X-Forwarded-For'] === [ '127.0.0.1', '127.0.0.2' ];
  // ctx.ips === [ '127.0.0.2' ];

request.subdomains

将子域作为数组返回。

子域是应用程序主域之前主机的点分隔部分。默认情况下,应用程序的域被假定为主机的最后两部分。这可以通过设置 app.subdomainOffset 来改变。

例如,如果域为“tobi.ferrets.example.com”:如果未设置 app.subdomainOffset(默认为2),则 ctx.subdomains 为 ['ferrets', 'tobi']。如果 app.subdomainOffset 为 3,则 ctx.subdomains 为 ['tobi']。

request.is(types...)

检查传入请求是否包含“Content-Type”标头字段,并且它包含任何给定的 mime 类型。如果没有请求正文,则返回 null。如果没有内容类型,或者匹配失败,则返回 false。否则,它返回匹配的内容类型。

// With Content-Type: text/html; charset=utf-8
ctx.is('html'); // => 'html'
ctx.is('text/html'); // => 'text/html'
ctx.is('text/*', 'text/html'); // => 'text/html'

// When Content-Type is application/json
ctx.is('json', 'urlencoded'); // => 'json'
ctx.is('application/json'); // => 'application/json'
ctx.is('html', 'application/*'); // => 'application/json'

ctx.is('html'); // => false

例如,如果您想确保仅将图像发送到给定路由:

if (ctx.is('image/*')) {
  // process
} else {
  ctx.throw(415, 'images only!');
}

Content Negotiation

Koa 的请求对象包括由 AcceptNegotiator 提供支持的有用的内容协商实用程序。这些实用程序是:

  • request.accepts(types)
  • request.acceptsEncodings(types)
  • request.acceptsCharsets(charsets)
  • request.acceptsLanguages(langs)

如果未提供任何类型,则返回所有可接受的类型。

如果提供了多种类型,则将返回最佳匹配。如果未找到匹配项,则返回 false,并且您应该向客户端发送 406“不可接受”响应。

如果缺少可接受的任何类型的接受标头,则将返回第一个类型。因此,您提供的类型的顺序很重要。

request.accepts(types)

检查给定类型是否可接受,如果为true则返回最佳匹配,否则为false。type 值可以是一个或多个 mime 类型字符串,如“application/json”,扩展名如“json”,或数组[“json”,“html”,“text/plain”]。

// Accept: text/html
ctx.accepts('html');
// => "html"

// Accept: text/*, application/json
ctx.accepts('html');
// => "html"
ctx.accepts('text/html');
// => "text/html"
ctx.accepts('json', 'text');
// => "json"
ctx.accepts('application/json');
// => "application/json"

// Accept: text/*, application/json
ctx.accepts('image/png');
ctx.accepts('png');
// => false

// Accept: text/*;q=.5, application/json
ctx.accepts(['html', 'json']);
ctx.accepts('html', 'json');
// => "json"

// No Accept header
ctx.accepts('html', 'json');
// => "html"
ctx.accepts('json', 'html');
// => "json"

您可以根据需要多次调用 ctx.accepts(),活着使用switch :

switch (ctx.accepts('json', 'html', 'text')) {
  case 'json': break;
  case 'html': break;
  case 'text': break;
  default: ctx.throw(406, 'json, html, or text only');
}

request.acceptsEncodings(encodings)

检查编码是否可接受,为true时返回最佳匹配,否则为false。请注意,您应该将identity作为编码之一!

// Accept-Encoding: gzip
ctx.acceptsEncodings('gzip', 'deflate', 'identity');
// => "gzip"

ctx.acceptsEncodings(['gzip', 'deflate', 'identity']);
// => "gzip"

当没有给出参数时,所有接受的编码都作为数组返回:

// Accept-Encoding: gzip, deflate
ctx.acceptsEncodings();
// => ["gzip", "deflate", "identity"]

请注意,如果客户端显式发送 identity;q=0,则identity编码(这意味着没有编码)可能是不可接受的。

request.acceptsCharsets(charsets)

检查字符集是否可接受,如果为 true,则返回最佳匹配,否则为 false。

// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets('utf-8', 'utf-7');
// => "utf-8"

ctx.acceptsCharsets(['utf-7', 'utf-8']);
// => "utf-8"

当没有给出参数时,所有接受的字符集都作为数组返回:

// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets();
// => ["utf-8", "utf-7", "iso-8859-1"]

request.acceptsLanguages(langs)

查语言是否可以接受,如果为真则返回最佳匹配,否则为false。

// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages('es', 'en');
// => "es"

ctx.acceptsLanguages(['en', 'es']);
// => "es"

当没有给出参数时,所有接受的语言都作为数组返回:

// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages();
// => ["es", "pt", "en"]

request.idempotent

检查请求是否是幂等的。

request.socket

返回请求套接字。

request.get(field)

返回带有不区分大小写字段的请求标头。

Response

Koa Response对象是节点普通响应对象之上的抽象,提供了对日常 HTTP 服务器开发有用的附加功能。

API

response.header

响应头对象。

response.headers

响应头对象。response.header别名

response.socket

响应套接字。指向 net.Socket 实例作为 request.socket。

response.status

获取响应状态。默认情况下,response.status 设置为 404,这与Node的 res.statusCode 默认设置为 200 不同。

response.status=

通过数字代码设置响应状态:

  • 100 "continue"
  • 101 "switching protocols"
  • 102 "processing"
  • 200 "ok"
  • 201 "created"
  • 202 "accepted"
  • 203 "non-authoritative information"
  • 204 "no content"
  • 205 "reset content"
  • 206 "partial content"
  • 207 "multi-status"
  • 208 "already reported"
  • 226 "im used"
  • 300 "multiple choices"
  • 301 "moved permanently"
  • 302 "found"
  • 303 "see other"
  • 304 "not modified"
  • 305 "use proxy"
  • 307 "temporary redirect"
  • 308 "permanent redirect"
  • 400 "bad request"
  • 401 "unauthorized"
  • 402 "payment required"
  • 403 "forbidden"
  • 404 "not found"
  • 405 "method not allowed"
  • 406 "not acceptable"
  • 407 "proxy authentication required"
  • 408 "request timeout"
  • 409 "conflict"
  • 410 "gone"
  • 411 "length required"
  • 412 "precondition failed"
  • 413 "payload too large"
  • 414 "uri too long"
  • 415 "unsupported media type"
  • 416 "range not satisfiable"
  • 417 "expectation failed"
  • 418 "I'm a teapot"
  • 422 "unprocessable entity"
  • 423 "locked"
  • 424 "failed dependency"
  • 426 "upgrade required"
  • 428 "precondition required"
  • 429 "too many requests"
  • 431 "request header fields too large"
  • 500 "internal server error"
  • 501 "not implemented"
  • 502 "bad gateway"
  • 503 "service unavailable"
  • 504 "gateway timeout"
  • 505 "http version not supported"
  • 506 "variant also negotiates"
  • 507 "insufficient storage"
  • 508 "loop detected"
  • 510 "not extended"
  • 511 "network authentication required"

注意:不要太担心记住这些字符串,如果你有错字,会抛出一个错误,显示这个列表以便你进行更正。

由于 response.status 默认设置为 404,因此要发送没有正文和不同状态的响应,如下所示:

ctx.response.status = 200;

// Or whatever other status
ctx.response.status = 204;

response.message

获取响应状态消息。默认情况下,response.message 与 response.status 相关联。

response.message=

将响应状态消息设置为给定值。

response.length

存在时以数字形式返回响应 Content-Length,或者在可能的情况下从 ctx.body 推导出来,或者undefined。

response.length=

将响应内容长度设置为给定值。

response.body

获取响应正文

response.body=

将响应正文设置为以下之一:

  • string written
  • Buffer written
  • Stream piped
  • Object || Array json-stringified
  • null || undefined no content response

如果没有设置 response.status,Koa 会根据 response.body 自动设置 status 为 200 或 204。具体来说,如果 response.body 没有设置或者已经设置为 null 或 undefined,Koa 会自动设置 response.status 为 204。如果您真的不想发送其他状态的内容响应,您应该通过以下方式覆盖 204 状态:

// This must be always set first before status, since null | undefined
// body automatically sets the status to 204
ctx.body = null;
// Now we override the 204 status with the desired one
ctx.status = 200;

Koa 并没有防范所有可以作为响应体的东西——一个函数没有有意义的序列化,根据您的应用程序返回一个布尔值可能是有意义的,虽然错误有效,但它可能无法像某些预期的那样工作错误的属性不可枚举。

app.use(async (ctx, next) => {
  await next()
  ctx.assert.equal('object', typeof ctx.body, 500, 'some dev did something wrong')
})

String

Content-Type 默认为 text/html 或 text/plain,两者都具有 utf-8 的默认字符集。Content-Length 字段也被设置。

Buffer

Content-Type 默认为 application/octet-stream,并且 Content-Length 也被设置。

Stream

Content-Type 默认为 application/octet-stream。每当将流设置为响应主体时, .onerror 都会自动添加为错误事件的侦听器以捕获任何错误。此外,只要请求关闭(甚至是过早关闭),流就会被销毁。如果您不想要这两个功能,请不要直接将流设置为主体。例如,在代理中将主体设置为 HTTP 流时,您可能不希望这样做,因为它会破坏底层连接。

有关更多信息,请参阅:github.com/koajs/koa/p…

这是一个不自动销毁流的流错误处理示例:

const PassThrough = require('stream').PassThrough;

app.use(async ctx => {
  ctx.body = someHTTPStream.on('error', (err) => ctx.onerror(err)).pipe(PassThrough());
});

Object

Content-Type 默认为 application/json。这包括普通对象 { foo: 'bar' } 和数组 ['foo', 'bar']。

response.get(field)

获取带有不区分大小写字段的响应标头字段值。

const etag = ctx.response.get('ETag');

response.has(field)

如果由名称标识的标头当前设置在传出标头中,则返回 true。标头名称匹配不区分大小写

const rateLimited = ctx.response.has('X-RateLimit-Limit');

response.set(field, value)

设置响应头字段:

ctx.set('Cache-Control', 'no-cache');

response.append(field, value)

附加带有值 val 的附加标头字段。

ctx.append('Link', '<http://127.0.0.1/>');

response.set(fields)

用一个对象设置几个响应头字段:

ctx.set({
  'Etag': '1234',
  'Last-Modified': date
});

这委托给 setHeader 通过指定的键设置或更新标头,并且不会重置整个标头。

response.remove(field)

删除响应头字段

response.type

获取响应 Content-Type 参数,例如“charset”。

const ct = ctx.type;
// => "image/png"

response.type=

通过 mime 字符串或文件扩展名设置响应 Content-Type。

ctx.type = 'text/plain; charset=utf-8';
ctx.type = 'image/png';
ctx.type = '.png';
ctx.type = 'png';

注意:当为您选择适当的字符集时,例如 response.type = 'html' 将默认为“utf-8”,如果您需要覆盖字符集,请使用 ctx.set('Content-Type', 'text/html') 直接将响应头字段设置为值。

response.is(types...)

与 ctx.request.is() 非常相似。检查响应类型是否是提供的类型之一。这对于创建操纵响应的中间件特别有用。

例如,这是一个中间件,可以缩小除流之外的所有 HTML 响应。

const minify = require('html-minifier');

app.use(async (ctx, next) => {
  await next();

  if (!ctx.response.is('html')) return;

  let body = ctx.body;
  if (!body || body.pipe) return;

  if (Buffer.isBuffer(body)) body = body.toString();
  ctx.body = minify(body);
});

response.redirect(url, [alt])

执行 [302] 重定向到 url。

当 Referrer 不存在时,字符串“back”是特殊的,以提供 Referrer 支持 alt 或使用“/”。

ctx.redirect('back');
ctx.redirect('back', '/index.html');
ctx.redirect('/login');
ctx.redirect('http://google.com');

要更改 302 的默认状态,只需在此调用之前或之后分配状态。要更改主体,请在此调用之后分配它:

ctx.status = 301;
ctx.redirect('/cart');
ctx.body = 'Redirecting to shopping cart';

response.attachment([filename], [options])

将 Content-Disposition 设置为“附件”以向客户端发出提示下载的信号。可以选择指定下载的文件名和一些选项

response.headerSent

检查是否已发送响应标头。对于查看客户端是否会收到错误通知很有用。

response.lastModified

将 Last-Modified 标头作为日期返回(如果存在)

response.lastModified=

将 Last-Modified 标头设置为适当的 UTC 字符串。您可以将其设置为日期或日期字符串。

ctx.response.lastModified = new Date();

response.etag=

设置响应的 ETag,包括包装的 's.请注意,没有对应的 response.etag访问属性。

ctx.response.etag = crypto.createHash('md5').update(ctx.body).digest('hex');

response.vary(field)

改变field

response.flushHeaders()

刷新所有设置的标头,然后开始正文。

Links