koajs

请求

Koa Request 对象是 node 普通 request 对象之上的抽象, 提供了日常 HTTP server 中更多有用的功能.

API

request.header

请求头对象.

request.headers

req.header 的别名

request.method

请求方法.

request.method=

设置请求方法, 实现中间件时非常有用, 例如 methodOverride().

request.length

将请求的 Content-Length 返回为数字, 或 undefined.

request.url

获取请求 URL.

request.url=

设置请求 URL, 在 rewrites 时有用.

request.originalUrl

获取 original URL.

request.path

获取请求 pathname.

request.path=

设置请求 pathname, 如果有 query-string 则保持不变.

request.querystring

获取原始 query string, 不包含 ?.

request.querystring=

设置 query string.

request.search

获取原始 query string, 包含 ?.

request.search=

设置 query string.

request.host

获取 host, 不包含端口号. 当 app.proxy 为 true 时支持 X-Forwarded-Host, 否者就使用 Host.

request.hostname

获取 hostname 如果有的话. 当 app.proxy 设为 true 时支持 X-Forwarded-Host, 否则直接使用 Host.

request.type

获取请求 Content-Type 字段, 不包含参数, 如 "charset".

var ct = this.request.type;
// => "image/png"

request.charset

获取请求 charset, 没有返回 undefined

this.request.charset
// => "utf-8"

request.query

获取解析后的 query-string, 如果没有返回空对象. 注意: 该方法不支持嵌套解析.

例如 "color=blue&size=small":

{
  color: 'blue',
  size: 'small'
}

request.query=

根据给定的对象设置 query-string. 注意: 该方法不支持嵌套对象.

this.query = { next: '/login' };

request.fresh

检查请求缓存是否是 "fresh" 的, 即内容没有发生变化. 该方法用于在If-None-Match / ETag, If-Modified-Since, Last-Modified 之间进行缓存 negotiation. 这个应该在设置过这些响应 hearder 后会用到.

this.set('ETag', '123');

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

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

request.stale

相反与 req.fresh.

request.protocol

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

request.secure

简化版 this.protocol == "https" 用于检查请求是否通过 TLS 发送.

request.ip

请求 IP 地址. 当 app.proxy 为 true 时支持 X-Forwarded-Proto.

request.ips

当 X-Forwarded-For 存在并且 app.proxy 开启会返回一个有序(upstream -> downstream)的 ip 数组. 否则返回空数组.

request.subdomains

以数组形式返回子域名.

子域名是 host 逗号分隔主域名前面的部分. 默认主域名是 host 的最后两部分. 可以通过设置 app.subdomainOffset 调整.

例如, 架设域名是 "tobi.ferrets.example.com": 如果 app.subdomainOffset 没有设置, this.subdomains 为 ["ferrets", "tobi"]. 如果 app.subdomainOffset 设为 3, this.subdomains 为 ["tobi"].

request.is(types...)

检查请求是否包含 "Content-Type" 字段, 并且包含当前已知的 mime 'type'. 如果没有请求 body, 返回 undefined. 如果没有字段, 或不包含, 返回 false. 否则返回包含的 content-type.

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

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

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

例如, 如果你想确保指定的路由只返回图片:

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

Content Negotiation

Koa 的 请求 对象包含有用的内容 negotiation 方法, 这些方法由acceptsnegotiator 提供, 主要包括:

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

如果没有提供 types, 将会返回所有支持的 type

如果提供多个 type, 将会返回最符合的那个, 如果没有符合的类型, 将会返回 false, 这时你应该响应 406 "Not Acceptable" 给客户端

如果没有 accept headers, 即被认为可以接受任何 type, 会返回第一个 type, 这时提供的 type 顺序会非常重要

request.accepts(types)

检查给定的 type(s) 是否 acceptable, 如果是, 则返回最佳的匹配, 否则 false, 这时应该响应 406 "Not Acceptable".

type 值应该是一个或多个 mime 字符串, 例如 "application/json", 扩展名如 "json", 或数组 ["json", "html", "text/plain"]. 如果给定一个 list 或 array, 会返回最佳(best)匹配项.

如果请求 client 没有发送 Accept header, 会返回第一个 type.

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

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

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

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

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

this.accepts() 可以被多次调用, 或使用在 switch.

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

request.acceptsEncodings(encodings)

检查 encodings 是否被接受, 如果是返回最佳匹配, 否则返回 identity.

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

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

如果没有传递参数, 会返回所有可接受的 encodings 数组.

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

注意 identity 编码 (等同于没有编码) 不会被接受, 如果客户端明确的发送了 identity;q=0. 虽然这种情况很少发生, 但你需要手动处理该方法返回 false 情况.

request.acceptsCharsets(charsets)

检查 charsets 是否被接受, 如果是返回最佳匹配, 否则 undefined.

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

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

如果没有传递参数, 会返回所有可接受 charsets 数组.

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

检查 langs 是否被接受, 如果是返回最佳匹配, 否则返回 undefined.

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

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

如果没有传递参数, 会返回所有可接受的 lang 数组.

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

request.idempotent

判断请求是否是 idempotent.

request.socket

返回请求 socket.

request.get(field)

返回请求 header.