Koajs 知识点速查

NPM version Downloads Repo Dependents Github repo

基于 Node.js 平台的下一代 web 开发框架,包含 Koa 的 API 参考列表和一些示例

入门

Hello World

Koa 需要 node v7.6.0 或更高版本来支持ES2015、异步方法,你可以安装自己支持的 node 版本

  • 安装依赖

    $ mkdir myapp # 创建目录
    $ cd myapp    # 进入目录
    $ nvm install 7
    $ npm init -y # 初始化一个配置
    $ npm install koa # 安装依赖
    
  • 入口文件 index.js 添加代码:

    const Koa = require('koa');
    const app = new Koa();
    
    app.use(async ctx => {
      ctx.body = 'Hello World';
    });
    
    app.listen(3000);
    
  • 使用以下命令运行应用程序

    $ node index.js
    

级联

const Koa = require('koa');
const app = new Koa();
// X-Response-Time x 响应时间
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
});
// 记录器 logger
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(
    `${ctx.method} ${ctx.url} - ${ms}`
  );
});
// 响应 response
app.use(async ctx => {
  ctx.body = 'Hello World';
});
app.listen(3000);

配置

:-:-
app.env默认为 NODE_ENVdevelopment
app.keys签名 cookie 密钥数组
app.proxy何时信任真正的代理头字段
app.subdomainOffset要忽略的 .subdomains 的偏移量,默认为 2
app.proxyIpHeader代理 ip 头,默认为 X-Forwarded-For
app.maxIpsCount从代理 ip 头读取的最大 ips 数,默认为 0(表示无穷大)

app.callback()

:-:-
app.listen(...) #为一个绑定 3000 端口的简单 Koa 应用
app.callback() #返回一个适合 http.createServer() 方法的回调函数用来处理请求
app.use(function) #添加指定的中间件,详情请看 Middleware
app.keys #设置签名 cookie 密钥
app.context #从中创建 ctx 的原型

错误处理

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

默认情况下 Koa 会将所有错误信息输出到 stderr, 除非 app.silenttrue。当 err.status404 或者 err.expose 时,默认错误处理程序也不会输出错误

Context 示例

app.use(async ctx => {
  ctx; // 这是上下文 Context
  ctx.request;  // 这是 koa Request
  ctx.response; // 这是 koa Response
});

app.listen(...)

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

这意味着您可以同时支持 HTTPSHTTPS,或者在 多个端口 监听同一个应用

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

ctx.throw 示例

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

this.throw('name required', 400) 等价于

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

ctx.assert 示例

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

Context(上下文) API

:-:-
ctx.reqNode 的 request 对象
ctx.resNode 的 response 对象
ctx.requestKoa 的 Request 对象
ctx.responseKoa 的 Response 对象
ctx.state推荐的命名空间,用于通过中间件传递信息到前端视图
ctx.app应用实例引用
ctx.app.emit发出由第一个参数定义的类型的事件
ctx.cookies.get(name, [options])获得 cookie 中名为 name 的值
ctx.cookies.set(name, value, [options])设置 cookie 中名为 name 的值
ctx.throw([status], [msg], [properties])抛出包含 .status 属性的错误,默认为 500
ctx.assert(value, [status], [msg], [properties])!value 时, Helper 方法抛出一个类似 .throw() 的错误
ctx.respond避免使用 Koa 的内置响应处理功能,您可以直接赋值 this.repond = false

ctx.cookies.set 参数

:-:-
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(映射为“strect”)
signed一个布尔值,指示是否对cookie进行签名(默认为false)。如果这是真的,还将发送另一个附加了.sig后缀的同名cookie,其中一个27字节的url安全base64 SHA1值表示cookie name=cookie值相对于第一个Keygrip键的哈希值。此签名密钥用于在下次收到cookie时检测篡改
overwrite一个布尔值,指示是否覆盖以前设置的同名 cookie(默认为false)。如果为true,则在设置此Cookie时,将从set-Cookie标头中筛选出在同一请求期间设置的具有相同名称的所有Cookie(无论路径或域如何)

请求(Request)

:-:-
request.header请求头对象
request.header=设置请求头对象
request.headers请求头对象。等价于 request.header.
request.headers=设置请求头对象。 等价于request.header=.
request.method请求方法
request.method=设置请求方法, 在实现中间件时非常有用,比如 methodOverride()
request.length以数字的形式返回 request 的内容长度(Content-Length),或者返回 undefined。
request.url获得请求url地址.
request.url=设置请求地址,用于重写url地址时
request.originalUrl获取请求原始地址
request.origin获取URL原始地址, 包含 protocol 和 host
request.href获取完整的请求URL, 包含 protocol, host 和 url
request.path获取请求路径名
request.path=设置请求路径名并保留当前查询字符串
request.querystring获取查询参数字符串(url中?后面的部分),不包含?
request.querystring=设置原始查询字符串
request.search获取查询参数字符串,包含?
request.search=设置原始查询字符串
request.host获取 host (hostname:port)。 当 app.proxy 设置为 true 时,支持 X-Forwarded-Host
request.hostname获取 hostname。当 app.proxy 设置为 true 时,支持 X-Forwarded-Host。
request.URL获取 WHATWG 解析的对象.
request.type获取请求 Content-Type,不包含像 "charset" 这样的参数。
request.charset获取请求 charset,没有则返回 undefined
request.query将查询参数字符串进行解析并以对象的形式返回,如果没有查询参数字字符串则返回一个空对象
request.query=根据给定的对象设置查询参数字符串
request.fresh检查请求缓存是否 "fresh"(内容没有发生变化)
request.stale与 req.fresh 相反
request.protocol返回请求协议,"https" 或者 "http"
request.secure简化版 this.protocol == "https",用来检查请求是否通过 TLS 发送
request.ip请求远程地址,当 app.proxy 设置为 true 时,支持 X-Forwarded-Host
request.ips当 X-Forwarded-For 存在并且 app.proxy 有效,将会返回一个有序(从 upstream 到 downstream)ip 数组
request.subdomains以数组形式返回子域名
request.is(types...)检查请求所包含的 "Content-Type" 是否为给定的 type 值
request.accepts(types)检查给定的类型 types(s) 是否可被接受,当为 true 时返回最佳匹配,否则返回 false
request.acceptsEncodings(encodings)检查 encodings 是否可以被接受,当为 true 时返回最佳匹配,否则返回 false
request.acceptsCharsets(charsets)检查 charsets 是否可以被接受,如果为 true 则返回最佳匹配,否则返回 false
request.acceptsLanguages(langs)检查 langs 是否可以被接受,如果为 true 则返回最佳匹配,否则返回 false
request.idempotent检查请求是否为幂等(idempotent)
request.socket返回请求的socket
request.get(field)返回请求头

响应(Response)

:-:-
response.headerResponse header 对象
response.headersResponse header 对象。等价于 response.header.
response.socketRequest socket.
response.status获取响应状态。 默认情况下,response.status设置为404,而不像node's res.statusCode默认为200。
response.status=通过数字设置响应状态
response.message获取响应状态消息。默认情况下, response.message关联response.status。
response.message=将响应状态消息设置为给定值。
response.length=将响应Content-Length设置为给定值。
response.length如果 Content-Length 作为数值存在,或者可以通过 ctx.body 来进行计算,则返回相应数值,否则返回 undefined。
response.body获取响应体。
response.body=设置响应体为如 string,Buffer,Stream,Object|Array,null
response.get(field)获取 response header 中字段值,field 不区分大小写
response.set(field, value)设置 response header 字段 field 的值为 value
response.append(field, value)添加额外的字段field 的值为 val
response.set(fields)使用对象同时设置 response header 中多个字段的值
response.remove(field)移除 response header 中字段 filed
response.type获取 response Content-Type,不包含像"charset"这样的参数
response.type=通过 mime 类型的字符串或者文件扩展名设置 response Content-Type
response.is(types...)ctx.request.is() 非常类似。用来检查响应类型是否是所提供的类型之一
response.redirect(url, [alt])执行 [302] 重定向到对应 url
response.attachment([filename])设置 "attachment" 的 Content-Disposition,用于给客户端发送信号来提示下载
response.headerSent检查 response header 是否已经发送,用于在发生错误时检查客户端是否被通知。
response.lastModified如果存在 Last-Modified,则以 Date 的形式返回。
response.lastModified=以 UTC 格式设置 Last-Modified。您可以使用 Date 或 date 字符串来进行设置。
response.etag=设置 包含 "s 的 ETag
response.vary(field)不同于field.
response.flushHeaders()刷新任何设置的响应头,并开始响应体

请求(Request)别名

以下访问器和别名与 Request 等价:

  • 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)别名

以下访问器和别名与 Response 等价:

  • 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.fresh 示例

// freshness 检查需要状态 20x 或 304
ctx.status = 200;
ctx.set('ETag', '123');

// 缓存正常
if (ctx.fresh) {
  ctx.status = 304;
  return;
}

// 缓存已过时
// 获取新数据
ctx.body = await db.find('something');

ctx.is 示例

// Content-Type: text/html; charset=utf-8
ctx.is('html'); // => 'html'
ctx.is('text/html'); // => 'text/html'
ctx.is('text/*', 'text/html');
// => 'text/html'
// 当 Content-Type 为 application/json 时
ctx.is('json', 'urlencoded'); // => 'json'
ctx.is('application/json');
// => 'application/json'
ctx.is('html', 'application/*');
// => 'application/json'

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

ctx.accepts 示例

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

request.acceptsCharsets 示例

// 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"

检查 charsets 是否可以被接受,如果为 true 则返回最佳匹配, 否则返回 false

response.set 示例

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

使用对象同时设置 response header 中多个字段的值

response.type 示例

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

获取 response Content-Type,不包含像"charset"这样的参数