options 参数详解

options 参数详解

由于 HTTP 请求的复杂性,导致 httpclient.request(url, options) 的 options 参数会非常多。接下来将会以参数说明和代码配合一起讲解每个可选参数的实际用途。

HttpClient 默认全局配置

// config/config.default.js
exports.httpclient = {
  // 是否开启本地 DNS 缓存,默认关闭,开启后有两个特性
  // 1. 所有的 DNS 查询都会默认优先使用缓存的,即使 DNS 查询错误也不影响应用
  // 2. 对同一个域名,在 dnsCacheLookupInterval 的间隔内(默认 10s)只会查询一次
  enableDNSCache: false,
  // 对同一个域名进行 DNS 查询的最小间隔时间
  dnsCacheLookupInterval: 10000,
  // DNS 同时缓存的最大域名数量,默认 1000
  dnsCacheMaxLength: 1000,

  request: {
    // 默认 request 超时时间
    timeout: 3000,
  },

  httpAgent: {
    // 默认开启 http KeepAlive 功能
    keepAlive: true,
    // 空闲的 KeepAlive socket 最长可以存活 4 秒
    freeSocketTimeout: 4000,
    // 当 socket 超过 30 秒都没有任何活动,就会被当作超时处理掉
    timeout: 30000,
    // 允许创建的最大 socket 数
    maxSockets: Number.MAX_SAFE_INTEGER,
    // 最大空闲 socket 数
    maxFreeSockets: 256,
  },

  httpsAgent: {
    // 默认开启 https KeepAlive 功能
    keepAlive: true,
    // 空闲的 KeepAlive socket 最长可以存活 4 秒
    freeSocketTimeout: 4000,
    // 当 socket 超过 30 秒都没有任何活动,就会被当作超时处理掉
    timeout: 30000,
    // 允许创建的最大 socket 数
    maxSockets: Number.MAX_SAFE_INTEGER,
    // 最大空闲 socket 数
    maxFreeSockets: 256,
  },
};

应用可以通过 config/config.default.js 覆盖此配置。

data: Object

需要发送的请求数据,根据 method 自动选择正确的数据处理方式。

  • GET,HEAD:通过 querystring.stringify(data) 处理后拼接到 url 的 query 参数上。
  • POST,PUT 和 DELETE 等:需要根据 contentType 做进一步判断处理。
    • contentType = json:通过 JSON.stringify(data) 处理,并设置为 body 发送。
    • 其他:通过 querystring.stringify(data) 处理,并设置为 body 发送。
// GET + data
ctx.curl(url, {
  data: { foo: 'bar' },
});

// POST + data
ctx.curl(url, {
  method: 'POST',
  data: { foo: 'bar' },
});

// POST + JSON + data
ctx.curl(url, {
  method: 'POST',
  contentType: 'json',
  data: { foo: 'bar' },
});

dataAsQueryString: Boolean

如果设置了 dataAsQueryString=true,那么即使在 POST 情况下,也会强制将 options.data 以 querystring.stringify 处理之后拼接到 url 的 query 参数上。

可以很好地解决以 stream 发送数据,且额外的请求参数以 url query 形式传递的应用场景:

ctx.curl(url, {
  method: 'POST',
  dataAsQueryString: true,
  data: {
    // 一般来说都是 access token 之类的权限验证参数
    accessToken: 'some access token value',
  },
  stream: myFileStream,
});

content: String|Buffer

发送请求正文,如果设置了此参数,那么会直接忽略 data 参数。

ctx.curl(url, {
  method: 'POST',
  // 直接发送原始 xml 数据,不需要 HttpClient 做特殊处理
  content: '<xml><hello>world</hello></xml>',
  headers: {
    'content-type': 'text/html',
  },
});

files: Mixed

文件上传,支持格式: String | ReadStream | Buffer | Array | Object。

ctx.curl(url, {
  method: 'POST',
  files: '/path/to/read',
  data: {
    foo: 'other fields',
  },
});

多文件上传:

ctx.curl(url, {
  method: 'POST',
  files: {
    file1: '/path/to/read',
    file2: fs.createReadStream(__filename),
    file3: Buffer.from('mock file content'),
  },
  data: {
    foo: 'other fields',
  },
});

stream: ReadStream

设置发送请求正文的可读数据流,默认是 null。一旦设置了此参数,HttpClient 将会忽略 data 和 content。

ctx.curl(url, {
  method: 'POST',
  stream: fs.createReadStream('/path/to/read'),
});

writeStream: WriteStream

设置接受响应数据的可写数据流,默认是 null。一旦设置此参数,那么返回值 result.data 将会被设置为 null,因为数据已经全部写入到 writeStream 中了。

ctx.curl(url, {
  writeStream: fs.createWriteStream('/path/to/store'),
});

consumeWriteStream: Boolean

是否等待 writeStream 完全写完才算响应全部接收完毕,默认是 true。此参数不建议修改默认值,除非我们明确知道它的副作用是可接受的,否则很可能会导致 writeStream 数据不完整。

method: String

设置请求方法,默认是 GET。支持 GET、POST、PUT、DELETE、PATCH 等所有 HTTP 方法。

contentType: String

设置请求数据格式,默认是 undefined,HttpClient 会自动根据 data 和 content 参数自动设置。data 是 object 的时候默认设置的是 form。支持 json 格式。

如需要以 JSON 格式发送 data:

ctx.curl(url, {
  method: 'POST',
  data: {
    foo: 'bar',
    now: Date.now(),
  },
  contentType: 'json',
});

dataType: String

设置响应数据格式,默认不对响应数据做任何处理,直接返回原始的 buffer 格式数据。支持 text 和 json 两种格式。

注意:设置成json 时,如果响应数据解析失败会抛 JSONResponseFormatError 异常。

const jsonResult = await ctx.curl(url, {
  dataType: 'json',
});
console.log(jsonResult.data);

const htmlResult = await ctx.curl(url, {
  dataType: 'text',
});
console.log(htmlResult.data);

fixJSONCtlChars: Boolean

是否自动过滤响应数据中的特殊控制字符 (U+0000 ~ U+001F),默认是 false。通常一些 CGI 系统返回的 JSON 数据会包含这些特殊控制字符,通过此参数可以自动过滤掉它们。

ctx.curl(url, {
  fixJSONCtlChars: true,
  dataType: 'json',
});

headers: Object

自定义请求头。

ctx.curl(url, {
  headers: {
    'x-foo': 'bar',
  },
});

timeout: Number|Array

请求超时时间,默认是 [ 5000, 5000 ],即创建连接超时是 5 秒,接收响应超时是 5 秒。

ctx.curl(url, {
  // 创建连接超时 3 秒,接收响应超时 3 秒
  timeout: 3000,
});

ctx.curl(url, {
  // 创建连接超时 1 秒,接收响应超时 30 秒,用于响应比较大的场景
  timeout: [ 1000, 30000 ],
});

agent: HttpAgent

允许通过此参数覆盖默认的 HttpAgent,如果你不想开启 KeepAlive,可以设置此参数为 false。

ctx.curl(url, {
  agent: false,
});

httpsAgent: HttpsAgent

允许通过此参数覆盖默认的 HttpsAgent,如果你不想开启 KeepAlive,可以设置此参数为 false。

ctx.curl(url, {
  httpsAgent: false,
});

auth: String

简单登录授权(Basic Authentication)参数,将以明文方式将登录信息以 Authorization 请求头发送出去。

ctx.curl(url, {
  // 参数必须按照 `user:password` 格式设置
  auth: 'foo:bar',
});

digestAuth: String

摘要登录授权(Digest Authentication)参数,设置此参数会自动对 401 响应尝试生成 Authorization 请求头,尝试以授权方式请求一次。

ctx.curl(url, {
  // 参数必须按照 `user:password` 格式设置
  digestAuth: 'foo:bar',
});

followRedirect: Boolean

是否自动跟进 3xx 的跳转响应,默认是 false。

ctx.curl(url, {
  followRedirect: true,
});

maxRedirects: Number

设置最大自动跳转次数,避免循环跳转无法终止,默认是 10 次。此参数不宜设置过大,它只在 followRedirect=true 情况下才会生效。

ctx.curl(url, {
  followRedirect: true,
  // 最大只允许自动跳转 5 次。
  maxRedirects: 5,
});

formatRedirectUrl: Function(from, to)

允许我们通过 formatRedirectUrl 自定义实现 302、301 等跳转 url 拼接, 默认是 url.resolve(from, to)。

ctx.curl(url, {
  formatRedirectUrl: (from, to) => {
    // 例如可在这里修正跳转不正确的 url
    if (to === '//foo/') {
      to = '/foo';
    }
    return url.resolve(from, to);
  },
});

beforeRequest: Function(options)

HttpClient 在请求正式发送之前,会尝试调用 beforeRequest 钩子,允许我们在这里对请求参数做最后一次修改。

ctx.curl(url, {
  beforeRequest: options => {
    // 例如我们可以设置全局请求 id,方便日志跟踪
    options.headers['x-request-id'] = uuid.v1();
  },
});

streaming: Boolean

是否直接返回响应流,默认为 false。开启 streaming 之后,HttpClient 会在拿到响应对象 res 之后马上返回,此时 result.headers 和 result.status 已经可以读取到,只是没有读取 data 数据而已。

const result = await ctx.curl(url, {
  streaming: true,
});

console.log(result.status, result.data);
// result.res 是一个 ReadStream 对象
ctx.body = result.res;

注意:如果 res 不是直接传递给 body,那么我们必须消费这个 stream,并且要做好 error 事件处理。

gzip: Boolean

是否支持 gzip 响应格式,默认为 false。开启 gzip 之后,HttpClient 将自动设置 Accept-Encoding: gzip 请求头,并且会自动解压带 Content-Encoding: gzip 响应头的数据。

ctx.curl(url, {
  gzip: true,
});

timing: Boolean

是否开启请求各阶段的时间测量,默认为 false。开启 timing 之后,可以通过 result.res.timing 拿到这次 HTTP 请求各阶段的时间测量值(单位是毫秒),通过这些测量值,我们可以非常方便地定位到这次请求最慢的环境发生在那个阶段,效果如同 Chrome network timing 的作用。

timing 各阶段测量值解析:

  • queuing:分配 socket 耗时
  • dnslookup:DNS 查询耗时
  • connected:socket 三次握手连接成功耗时
  • requestSent:请求数据完整发送完毕耗时
  • waiting:收到第一个字节的响应数据耗时
  • contentDownload:全部响应数据接收完毕耗时
const result = await ctx.curl(url, {
  timing: true,
});
console.log(result.res.timing);
// {
//   "queuing":29,
//   "dnslookup":37,
//   "connected":370,
//   "requestSent":1001,
//   "waiting":1833,
//   "contentDownload":3416
// }

ca,rejectUnauthorized,pfx,key,cert,passphrase,ciphers,secureProtocol

这几个都是透传给 [HTTPS] 模块的参数,具体请查看 https.request(options, callback)。