原文链接 Node Redis
Node Redis
安装
npm i redis
例子
const redis = require("redis");
const client = redis.createClient();
client.on("error", function(error) {
console.error(error);
});
client.set("key", "value", redis.print);
client.get("key", redis.print);
Note that the API is entirely asynchronous. To get data back from the server, you’ll need to use a callback.
注意,所有的API都是异步的,从服务器获取数据时,需要使用回调的方式
通过Promise的方式使用
Node Redis目前尚未支持原生的Promise写法(Promise的支持会在v4版本更新),如果你依然想要这种写法的,你也可以通过Node.js中的util.promisify
方法来支持Promise的写法。
const { promisify } = require("util");
const getAsync = promisify(client.get).bind(client);
getAsync.then(console.log).catch(console.error);
通过指令使用
Node Redis库是与Redis中的命令一一对应的。
每一个Redis命令都作为一个函数被暴露在了client
对象上。所有的方法都采用了数组输入参数后加一个callback回调,或者是前面可变数量的参数后加一个callback回调的格式进行传参。示例代码如下:
client.hmset(["key", "foo", "bar"], function(err, res) {
// ...
});
// Works the same as
client.hmset("key", ["foo", "bar"], function(err, res) {
// ...
});
// Or
client.hmset("key", "foo", "bar", function(err, res) {
// ...
});
如果可以使用数组(通过主体解析器、查询字符串或其他方法),则应特别注意入参,因为单个参数可能会无意中被解释为多个参数。
注意,无论采用哪种传参方式,callback回调选项都是可选的。
client.set("foo", "bar");
client.set(["hello", "world"]);
如果Redis中某个key允许为null时,如果不传key,会直接使用null代替。
client.get("missing_key", function(err, reply) {
// reply is null when the key is missing
console.log(reply);
});
Node Redis会对返回的结果进行最小化的解析。调用函数在返回数据时,整数和数组与JavaScript中的整数和数组并无差别;HGETALL
会返回一个使用hash keys作为键的对象。所有的字符串会根据你的设置,作为JavaScript中的字符串或者一个buffer返回。请注意,当参数或返回值为空值、undefined或者布尔值时,会被强制转换为字符串。
事件
数据库连接与其他事件
当连接到数据库服务器时,client
会根据状态触发一些特定的事件。
"ready"
一旦建立了连接,客户端将发出ready。在就绪事件之前发出的命令被排队,然后在发出此事件之前重放。
在连接准备就绪时client
会触发一次ready
事件。所有的在ready
事件触发前的命令都会被排成一个队列,然后在ready
事件触发前被以此调用。
"connect"
当连接上数据库服务时,client
会尽可能快地触发一个connect
事件
"reconnecting"
client
会触发reconnecting
事件当应用尝试重新连接到Redis服务器时。监听器会回传一个对象,该对象包含delay(前一次try的毫秒数)和attempt属性。
"error"
当应用在连接Redis服务时遇到错误或者Node Redis中发生任何其他错误时,client
都会触发error
事件。如果你使用不带回调的命令时遇到了ReplyError,那么这个错误会被发送到监听器上。因此,需要对监听器上的错误进行处理。
"end"
当一个可用的Redis服务连接被关闭时,client
会触发一个end
事件
"warning"
当设置了密码但不需要密码,或者使用了不推荐的option / function / similar
项时,client
会触发一个warning
事件。
API
redis.createClient()
If you have redis-server running on the same machine as node, then the defaults for port and host are probably fine and you don’t need to supply any arguments. createClient() returns a RedisClient object. Otherwise, createClient() accepts these arguments:
如果你的redis服务和你的node服务器运行在同一台机器上,那么port和host使用默认值即可,你不需要提供任何参数。createClient
返回一个RedisClient
对象。接收参数如下:
redis.createClient([options])
redis.createClient(unix_socket[, options])
redis.createClient(redis_url[, options])
redis.createClient(port[, host][, options])
Tip:如果Redis服务器与客户机运行在同一台机器上,请考虑尽可能使用unix sockets来提高吞吐量。
注意:使用rediss://...
作为redis_url
时,将启用TLS socket来进行连接。另外,如果需要的话你还可以在options中设置其他TLS选项。
options
选项
参数 | 默认值 | 说明 |
---|---|---|
host | 127.0.0.1 | redis服务ip地址 |
port | 6379 | redis服务端口 |
path | null | redis服务UNIX socket串 |
url | null | redis服务url,接收格式为[redis[s]:]//[[user][:password@]][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]] |
string_numbers | null | 当是指为true 时,Node Redis会将数据库中的数字转换成字符串。 |
return_buffers | false | 如果设置为true 时所有的callback中拿到的数据都会转换成Buffers |
detect_buffers | false | 如果设置为true 时callback中拿到的数据都会转换成Buffers,不同于return_buffers作用在所有命令上,该选项可以让你在命令执行前切换返回格式。注意,这个选项在pubsub模式下不起作用,订阅还是会返回原先固定的String格式或者Buffers |
socket_keepalive | true | 当设置为true时,底层socket会启用keep-alive。 |
socket_initial_delay | 0 | 单位为ms,这个选项也表示向redis发送信息的事件间隔。 |
no_ready_check | false | 当与Redis服务器建立连接时,服务器可能仍在从磁盘加载数据库。加载时,服务器不会响应任何命令。为了解决这个问题,Node Redis有一个“ready check”的机制,它向服务器发送INFO命令。INFO命令的响应指示服务器是否准备好接收更多命令。准备就绪后,Node Redis将发出ready 事件。设置为true来禁止此检查。 |
enable_offline_queue | true | 默认情况下,如果没有到Redis服务器的活动连接,则会将命令添加到队列中,并在建立连接后执行。设置为false将禁用此功能,回调将立即执行并抛出错误,如果未指定回调,则会发出错误。 |
retry_unfulfilled_commands | false | 如果设置成true,所有未执行的指令都会在连接重连时进行重试。如果使用状态状态更改命令(e.g. incr )时,请谨慎使用;如果使用了阻塞命令时这个选项尤其有用。 |
password | null | 如果设置了密码,客户端会在连接时自动运行auth 命令。该选项也可以使用别名auth_pass,注意当Node Redis版本低于2.5时,该选项必须使用auth_pass |
user | null | ACL用户,只有当password设置时才有用 |
db | null | 如果不为空,则客户端在连接时会自动执行select 命令 |
family | IPv4 | 可设置为’IPv6’。 |
disable_resubscribing | false | 如果设置为true,客户端会在连接中断时停止订阅 |
rename_commands | null | 可以传入一个对象用于对命令进行重命名。例如你想重命名KEYS 命令为DO-NOT-USE ,你需要传入{ KEYS : “DO-NOT-USE” },详情请参考Redis security topics |
tls | null | 包含需要传给tls.connect 选项的对象,用于创建Redis的TLS连接 |
prefix | null | 用于修改所有keys的前缀 |
retry_strategy | function | 一个用于接收一个options对象作为参数的函数,options中包括attempt (重试次数)、total_retry_time (自上一次连接以来经过的重试总时间)、times_connected (连接的总次数)、error (连接断开的原因)。如果该函数返回一个Number 类型,则重试将在该时间(单位ms)之后发生。如果返回的不是数字类型,则不会进行重试,所有未执行的命令都会抛出错误。 |
connect_timeout | 3600000 | 单位ms,仅作为连接到redis服务的超时时间,但如果同时在retry_strategy 中返回了一个Number ,那么connect_timeout 设置则会让retry_strategy 中的设置失效。 |
参数示例代码
detect_buffers example:
const redis = require("redis");
const client = redis.createClient({ detect_buffers: true });
client.set("foo_rand000000000000", "OK");
// This will return a JavaScript String
client.get("foo_rand000000000000", function(err, reply) {
console.log(reply.toString()); // Will print `OK`
});
// This will return a Buffer since original key is specified as a Buffer
client.get(new Buffer("foo_rand000000000000"), function(err, reply) {
console.log(reply.toString()); // Will print `<Buffer 4f 4b>`
});
retry_strategy example:
const client = redis.createClient({
retry_strategy: function(options) {
if (options.error && options.error.code === "ECONNREFUSED") {
// End reconnecting on a specific error and flush all commands with
// a individual error
return new Error("The server refused the connection");
}
if (options.total_retry_time > 1000 * 60 * 60) {
// End reconnecting after a specific timeout and flush all commands
// with a individual error
return new Error("Retry time exhausted");
}
if (options.attempt > 10) {
// End reconnecting with built in error
return undefined;
}
// reconnect after
return Math.min(options.attempt * 100, 3000);
},
});
client.auth(password[, callback])
当应用连接到redis服务时需要提供认证密码,auth
命令必须在连接后第一时间调用。因为重连以及就绪监测难以协调,所以auth
命令会保存密码然后再每一次连接及重连后发送密码到redis服务。callback
函数只会调用一次,触发的时机在首次auth
命令发送到服务器并返回结果时。注意,你不能在ready
监听钩子中调用clien.auth
否则会抛出一个错误Error: Ready check failed: ERR operation not permitted.
client.quit(callback)
向redis服务发送断开连接命令,在正确处理所有正在运行的所有命令之后平滑地断开连接。如果该命令在重连时被调用(重连时不存在redis连接),这个命令会立即停止连接,而不是导致再一次的重连,在这种情况下所有未被执行的指令都将抛出错误。
client.end(flush)
强行断开与redis服务的连接。注意,这个命令不会等待未返回的命令执行完毕。如果你想平滑地断开连接请使用client.quit
。当你不是百分比确定其他的命令是否重要时,你可以把flush设置为true。如果flush被设置为false,那么正在执行的命令会立即抛出错误。
强行断开连接的例子,你特喵不会想这么做的。
const redis = require("redis");
const client = redis.createClient();
client.set("hello", "world", function(err) {
// This will either result in an error (flush parameter is set to true)
// or will silently fail and this callback will not be called at all (flush set to false)
console.error(err);
});
// No further commands will be processed
client.end(true);
client.get("hello", function(err) {
console.error(err); // => 'The connection has already been closed.'
});
client.end()
不传flush参数时flush会被设置成true,在生产环境下需慎用。
错误类型
错误子类型如下:
RedisError
:所有错误的父类ReplyError
:RedisError
的子类,redis本身的错误AbortError
:RedisError
的子类,当命令因某些因素未完成时抛出ParserError
:RedisError
的子类,当发生解析错误时抛出AggregateError
:AbortError
的子类,当命令回调中发生多个错误时抛出,这时不会抛出多个AbortError
例子
const assert = require("assert");
const redis = require("redis");
const { AbortError, AggregateError, ReplyError } = require("redis");
const client = redis.createClient();
client.on("error", function(err) {
assert(err instanceof Error);
assert(err instanceof AbortError);
assert(err instanceof AggregateError);
// The set and get are aggregated in here
assert.strictEqual(err.errors.length, 2);
assert.strictEqual(err.code, "NR_CLOSED");
});
client.set("foo", "bar", "baz", function(err, res) {
// Too many arguments
assert(err instanceof ReplyError); // => true
assert.strictEqual(err.command, "SET");
assert.deepStrictEqual(err.args, ["foo", 123, "bar"]);
redis.debug_mode = true;
client.set("foo", "bar");
client.get("foo");
process.nextTick(function() {
// Force closing the connection while the command did not yet return
client.end(true);
redis.debug_mode = false;
});
});
所有的ReplyError
在抛出时都会带有命令名词以及参数
错误码
当客户端连接故障时,Node Redis 会返回一个NR_CLOSED
错误码。当一个命令未被正确执行时会返回一个UNCERTAIN_STATE
的状态码。CONNECTION_BROKEN
错误码代表着Node Redis放弃重连。
client.unref()
调用client.unref()
可以使程序在不挂起命令的情况下退出。
这是一个试验中的特性,并且只支持Redis协议的一个子集。一些需要保持客户端状态的命令,例如*SUBSCRIBE
又或者一些带有阻塞的命令如BL*
会在执行.unref()
后停止工作
const redis = require("redis");
const client = redis.createClient();
/*
* Calling unref() will allow this program to exit immediately after the get
* command finishes. Otherwise the client would hang as long as the
* client-server connection is alive.
*/
client.unref();
client.get("foo", function(err, value) {
if (err) throw err;
console.log(value);
});
Hash命令
很多的Redis命令使用单个字符或者是字符串作为参数或者是返回。在下面的这些api中处理hash值时有几个有用的方法。
client.hgetall(hash, callback)
在HGETALL
命令的返回中会被转换为一个对象,在这种情况下你可以使用JavaScript的语法
例如:
client.hmset("key", "foo", "bar", "hello", "world");
client.hgetall("key", function(err, value) {
console.log(value.foo); // > "bar"
console.log(value.hello); // > "world"
});
client.hmset(hash, key1, val1, ...keyN, valN, [callback])
可以通过多种方式设置多重值
例如:
// key
// 1) foo => bar
// 2) hello => world
client.HMSET("key", "foo", "bar", "hello", "world");