restify-clients中文文档|restify-clients js中文教程|解析
restify-clients
入门
安装模块: npm install restify-clients
用法
客户端接口
有三个独立的客户端:
- JsonClient:发送并期待 application/json
- StringClient:发送 url 编码的请求并期望文本/纯文本
- HttpClient:节点的 http/https 库的瘦包装器
这个想法是,如果你想支持“典型”的控制平面的REST API,你可能想的JsonClient
,或者如果你使用一些其他的序列化(如XML),你会写自己的客户端,它扩展了StringClient
。如果您需要流媒体支持,则需要在HttpClient
, asStringClient
和朋友缓冲请求/响应之上做一些工作。
所有客户端都支持指数退避重试以获取 TCP 连接;它们不会像之前版本的 restify 客户端那样对 5xx 错误代码执行重试。您可以设置retry
为false
完全禁用此逻辑。此外,所有客户端都支持一个connectTimeout
字段,该字段在每次重试时使用。默认值不是设置 a
connectTimeout
,因此您最终会使用 node.js 套接字默认值。
这是一个点击
Joyent CloudAPI 的例子:
var clients = require('restify-clients');
// Creates a JSON client
var client = clients.createJsonClient({
url: 'https://us-east-1.api.joyent.com'
});
client.basicAuth('$login', '$password');
client.get('/my/machines', function(err, req, res, obj) {
assert.ifError(err);
console.log(JSON.stringify(obj, null, 2));
});
简而言之,可以使用字符串 URL 而不是选项对象来初始化客户端:
var clients = require('restify-clients');
var client = clients.createJsonClient('https://us-east-1.api.joyent.com');
请注意,所有进一步的文档都是指get/put/del
采用字符串路径的方法的“简写”形式。您还可以将对象传递给任何带有额外参数(特别是标头)的方法:
var options = {
path: '/foo/bar',
headers: {
'x-foo': 'bar'
},
retry: {
'retries': 0
},
agent: false
};
client.get(options, function(err, req, res) { .. });
如果您需要在请求发送到服务器之前在请求中插入额外的标头,您可以signRequest
在创建客户端时提供同步回调函数作为
选项。这对于node-http-signature尤其有用
,它需要附加所选传出标头的加密签名。如果提供,将使用单个参数调用此回调:传出
http.ClientRequest
对象。
客户端
JSON Client 是与 restify 捆绑的最高级别的客户端;它导出一组直接映射到 HTTP 动词的方法。所有回调看起来像function(err, req, res, [obj])
,其中obj
是可选的,具体取决于是否返回了内容。HTTP 状态代码不会被解释,因此如果服务器返回 4xx 或带有 JSON 有效负载的内容,obj
则将是 JSON 有效负载。 err
但是,如果服务器返回状态代码 >= 400(这将是 restify HTTP 错误之一),则会被设置。如果obj
看起来像一个RestError
:
{
"code": "FooError",
"message": "some foo happened"
}
然后为您err
“上变频” RestError
。否则它将是一个HttpError
.
createJsonClient(选项)
var client = restify.createJsonClient({
url: 'https://api.us-east-1.joyent.com',
version: '*'
});
API 选项:
姓名 | 类型 | 描述 |
---|---|---|
接受 | 细绳 | 接受要发送的标头 |
追加路径 | 布尔值 | 将动词时间提供的路径附加到现有客户端路径 |
审计 | 布尔值 | 启用审计日志 |
审计员 | 功能 | 审计日志功能 |
连接超时 | 数字 | 等待套接字的时间 |
内容Md5 | 目的 | 如何处理响应 content-md5 标头。请参阅StringClient的contentMd5选项 |
内容类型 | 细绳 | 要发送的内容类型标头 |
请求超时 | 数字 | 等待请求完成的时间 |
跟踪 | 目的 | node-dtrace-provider 句柄 |
压缩包 | 目的 | 使用发送时将压缩数据 content-encoding: gzip
|
标题 | 目的 | 要在所有请求中设置的 HTTP 标头 |
日志 | 目的 | 班扬实例 |
询问 | 目的 | 通过 querystring 模块序列化的 querystring 对象 |
重试 | 目的 | 提供给节点重试的选项;“false”禁用重试;默认为 4 次重试 |
安全字符串化 | 布尔值 | 安全地序列化 JSON 对象,即循环依赖 |
签名请求 | 功能 | 用于在发送请求之前插入标头的同步回调 |
网址 | 细绳 | 要连接到的完全限定 URL |
用户代理 | 细绳 | 要使用的用户代理字符串;restify 插入一个,但你可以覆盖它 |
版本 | 细绳 | semver 字符串以设置接受版本 |
跟随重定向 | 布尔值 | 跟踪来自服务器的重定向 |
最大重定向 | 数字 | 要遵循的最大重定向数 |
代理 | 细绳 | 用于请求的 HTTP 代理 URL 字符串(或解析的 URL 对象)。如果未指定,则使用https_proxy 或http_proxy 环境变量。传递proxy: false 以明确禁用使用代理(即确保代理 URL 不会从环境变量中提取)。请参阅下面的代理部分。 |
无代理 | 细绳 | 不使用代理的主机的逗号分隔列表。如果未指定,则NO_PROXY 使用环境变量。可以通过noProxy: '' 将其显式设置为空并确保不使用可能的环境变量。请参阅下面的代理部分。 |
获取(路径,回调)
执行 HTTP 获取;如果没有返回有效负载,则obj
默认
{}
为您(因此您不会收到一堆空指针错误)。
client.get('/foo/bar', function(err, req, res, obj) {
assert.ifError(err);
console.log('%j', obj);
});
头(路径,回调)
就像get
,但没有obj
:
client.head('/foo/bar', function(err, req, res) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
});
后(路径,对象,回调)
获取一个完整的对象进行序列化并发送到服务器。
client.post('/foo', { hello: 'world' }, function(err, req, res, obj) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
console.log('%j', obj);
});
放置(路径,对象,回调)
就像post
:
client.put('/foo', { hello: 'world' }, function(err, req, res, obj) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
console.log('%j', obj);
});
删除(路径,回调)
del
不接受内容,因为您知道,它不应该:
client.del('/foo/bar', function(err, req, res) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
});
字符串客户端
StringClient
是JsonClient
建立在基础之上的,并为您编写其他缓冲/解析客户端(例如 XML 客户端)提供了基础。如果您需要与某个“原始”HTTP 服务器通信,那么
StringClient
这就是您想要的,因为默认情况下它会为您提供内容上传application/x-www-form-url-encoded
和下载为text/plain
. 要扩展 a StringClient
,请查看JsonClient
. 有效地,您扩展它,并在构造函数中设置适当的选项并实现write
(用于放置/发布)和parse
方法(用于所有 HTTP 主体),就是这样。
内容Md5
指定如何处理 content-md5 响应头的contentMd5
选项StringClient
:
var contentMd5 = {
ignore: false,
encodings: undefined
};
默认情况下,如果服务器使用content-md5
标头响应,StringClient
将自动验证响应主体 md5 哈希,并BadDigest
在不匹配时返回错误。您可以通过contentMd5.ignore
在创建 StringClient 实例时将该选项设置为 true来禁用此行为
。您还可以将该contentMd5.encodings
属性设置为StringClient 将用于验证 md5 的编码名称数组。节点 6 及更高版本的默认编码为“utf8”,节点 4 及更早版本的默认编码为“二进制”(latin1 编码)(因为节点在版本 4 和 6 之间更改了默认加密哈希编码)。要支持节点 4 和 6 服务器生成的 content-md5 哈希,您可以contentMd5.encodings = ["utf8", "binary"]
在创建 StringClient 实例时指定。
创建字符串客户端(选项)
var client = restify.createStringClient({
url: 'https://example.com'
});
获取(路径,回调)
执行 HTTP 获取;如果没有返回有效负载,则data
默认
''
为您(因此您不会收到一堆空指针错误)。
client.get('/foo/bar', function(err, req, res, data) {
assert.ifError(err);
console.log('%s', data);
});
头(路径,回调)
就像get
,但没有data
:
client.head('/foo/bar', function(err, req, res) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
});
后(路径,对象,回调)
获取一个完整的对象进行序列化并发送到服务器。
client.post('/foo', { hello: 'world' }, function(err, req, res, data) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
console.log('%s', data);
});
放置(路径,对象,回调)
就像post
:
client.put('/foo', { hello: 'world' }, function(err, req, res, data) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
console.log('%s', data);
});
删除(路径,回调)
del
不接受内容,因为您知道,它不应该:
client.del('/foo/bar', function(err, req, res) {
assert.ifError(err);
console.log('%d -> %j', res.statusCode, res.headers);
});
客户端
HttpClient
是 restify 中提供的最低级别的客户端,基本上只是节点 http/https 模块顶部的一些糖(使用与其他客户端一样的 HTTP 方法)。如果您想使用 restify 进行流式传输,这很有用。请注意,不幸的是,下面的事件被命名result
而不是response
(因为
事件“响应”
已被使用)。
client = restify.createClient({
url: 'http://127.0.0.1'
});
client.get('/str/mcavage', function(err, req) {
assert.ifError(err); // connection error
req.on('result', function(err, res) {
assert.ifError(err); // HTTP status code >= 400
res.body = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
res.body += chunk;
});
res.on('end', function() {
console.log(res.body);
});
});
});
或者写:
client.post(opts, function(err, req) {
assert.ifError(connectErr);
req.on('result', function(err, res) {
assert.ifError(err);
res.body = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
res.body += chunk;
});
res.on('end', function() {
console.log(res.body);
});
});
req.write('hello world');
req.end();
});
请注意, get/head/del 都会req.end()
为您调用,因此您无法在它们之上写入数据。否则,所有相同的方法都与
JsonClient/StringClient
.
希望扩展的人HttpClient
应该查看内部结构并注意read
并且write
可能需要被覆盖。
代理
一的RESTify客户端可以使用HTTP代理,或者通过选项createClient
或通过http_proxy
,https_proxy
以及NO_PROXY
环境变量中的许多工具(例如,公共curl
)。
restify.createClient({
proxy: <proxy url string or object>,
noProxy: <boolean>
});
指定代理 URL的proxy
选项createClient
,例如:
proxy: 'http://user:password@example.com:4321'
或者可以给出一个代理对象。(警告:如果您的代理 URL 具有身份验证信息,则该proxyAuth
字段不是简单的require('url').parse()
会产生的。)
proxy: {
protocol: 'http:',
host: 'example.com',
port: 4321,
proxyAuth: 'user:password'
}
或者proxy: false
可以明确禁用使用代理——即确保代理 URL 不会从环境变量中提取。
如果未指定,则以下环境变量(按给定顺序)用于获取代理 URL:
HTTPS_PROXY
https_proxy
HTTP_PROXY
http_proxy
注意:restify(-clients) 的未来主要版本可能会更改此环境变量行为。请参阅有关此问题的讨论。
该noProxy
选项可用于排除某些主机使用给定代理。如果未指定,则使用NO_PROXY
orno_proxy
环境变量。使用noProxy: ''
覆盖可能的环境变量,但不能匹配任何主机。
该值是一个字符串,给出一组以逗号分隔的主机、主机部分后缀或特殊的“*”以指示所有主机。(其定义旨在匹配 curl 的NO_PROXY
环境变量。)一些示例:
$ export NO_PROXY='*' # don't proxy requests to any urls
$ export NO_PROXY='127.0.0.1' # don't proxy requests the localhost IP
$ export NO_PROXY='localhost:8000' # ... 'localhost' hostname and port 8000
$ export NO_PROXY='google.com' # ... "google.com" and "*.google.com"
$ export NO_PROXY='www.google.com' # ... "www.google.com"
$ export NO_PROXY='127.0.0.1, google.com' # multiple hosts
注意:请求的 url 必须将完整主机名或主机名部分与“.”NO_PROXY=oogle.com
匹配:与“google.com”不匹配。不执行 DNS 查找来确定主机名的 IP 地址。
basicAuth(用户名,密码)
由于尚未提及,此便捷方法(适用于所有客户端)只需设置Authorization
所有 HTTP 请求的标头即可:
client.basicAuth('mark', 'mysupersecretpassword');
升级
如果你成功地协商与HTTP服务器进行升级的
upgradeResult
活动将与参数发射err
,res
,socket
和head
。您可以使用此功能与服务器建立 WebSockets 连接。例如,使用
分水岭库:
var ws = new Watershed();
var wskey = ws.generateKey();
var options = {
path: '/websockets/attach',
headers: {
connection: 'upgrade',
upgrade: 'websocket',
'sec-websocket-key': wskey,
}
};
client.get(options, function(err, res, socket, head) {
res.once('upgradeResult', function(err2, res2, socket2, head2) {
var shed = ws.connect(res2, socket2, head2, wskey);
shed.on('text', function(msg) {
console.log('message from server: ' + msg);
shed.end();
});
shed.send('greetings program');
});
});
常用API
以下方法为所有版本的客户端共享:
机上请求()
返回客户端当前正在处理的进行中请求的数量。一旦调用动词方法,请求计数就会增加,这意味着飞行中的请求被定义为处于以下任一状态的请求:
- 在调用动词函数之后但在任何 I/O 之前
- 等待 I/O(DNS 解析、套接字连接、服务器响应等)
- 请求序列化(上传请求体等)
- 响应编组/消耗
当end
发出响应的事件或发出请求的error
事件时,计数器递减。
活动
客户端发出以下事件:
client.on(‘timings’, function(timings) {… });
每个请求的时间可以req.getTimings()
通过一个timings
事件在客户端或从客户端发出,以毫秒为单位:
{
dnsLookup: 34,
tcpConnection: 52,
tlsHandshake: 112,
firstByte: 66,
contentTransfer: 2,
total: 266
}
除了total
可以null
在各种情况下(例如保持活动连接,缺少 https 等)之外的所有时间。
client.on(‘metrics’, function(metrics) {… });
每个请求的指标在该req.getMetrics()
方法下可用,并且也通过metrics
事件从客户端发出:
{
statusCode: 200,
method: 'POST',
success: true,
path: '/foo/bar',
url: 'http://netflix.com',
timings: {
dnsLookup: 34,
tcpConnection: 52,
tlsHandshake: 112,
firstByte: 66,
contentTransfer: 2,
total: 266
}
}
client.on(‘after’, function(req, res, err) {… });
客户端将after
在每个完成的请求(成功与否)后发出一个事件。这对于附加后处理程序以报告指标或有关客户端的其他有用信息非常有用。使用此事件时,时间和指标信息可通过请求 getter
req.getTimings()
和req.getMetrics()
.
对于 StringClient 和 JSONClient,在after
接收和解析响应后触发事件。对于 HttpClient 来说,用法有点微妙,下面会介绍。
after
事件与 HttpClient 一起使用
将由于低级 HttpClient 的回调接口将关联的请求和响应流直接公开给消费者,因此在after
与 HttpClient 一起使用时有一些注意事项。消费者必须使用响应流(通过使用data
响应上的事件)才能after
触发事件。例如,下面是 HttpClient 实例如何使用响应的数据来触发after
事件:
httpClient.get('/200', function (err, req) {
req.on('result', function (err, res) {
let body = '';
// must consume the stream first
res.on('data', function (chunk) {
body += chunk;
});
});
});
httpClient.once('after', function (req, res, err) {
// this is fired after response's `end` event.
});
由于 HttpClient 的低级性质造成的另一个影响意味着在消费回调中创建的任何错误都不会在after
事件中自动可用。例如,如果您得到 500,但随后确定您的有效负载有一些错误或格式错误的数据,或者您在使用流时遇到错误,after
如果您想稍后使用它,则您有责任将其传播回
:
httpClient.get('/500', function (err, req) {
req.on('result', function (err, res) {
// err is an InternalServerError here. but a 500 could still return
// some data like an error message, so let's parse the response now.
res.on('data', function (chunk) {
// parse the chunks here...
// oh no, bad data! but how do I get this error to the after event?
var invalidDataError = new Error('invalid data format!');
// attach it to the req or res object
req.httpClientError = invalidDataError;
});
});
});
httpClient.once('after', function (req, res, err) {
// err will be an InternalServerError, and req.httpClientError will be your
// custom error.
});
在超时场景(连接超时或请求超时)中,没有响应消费,在这种情况下客户端的after
事件与请求的result
事件同时被触发。
贡献
为任何新的或更改的功能添加单元测试。确保 lint 和样式检查通过。确保您的提交消息遵循传统的提交
规范。
要开始贡献,请安装 git pre-push 钩子:
make githooks
在提交之前,运行 prepush 钩子:
make prepush
如果您有样式错误,您可以通过运行来自动修复空格问题:
make codestyle-fix
剪切发布
为了发布新版本的 restify-clients 模块:
make release
这将运行发布目标,它将:
- 自动更新变更日志。
- 使用自上次发布以来在 git 历史记录中找到的常规提交消息,自动增加适当的版本号。
- 将 git 标签推送到原点
- 称呼
npm publish
执照
版权所有 (c) 2015 Alex Liu
在 MIT 许可下获得许可。