在get
上发现了奇怪的数据损坏。
在Docker +节点版本6.3.0和5.12.0中尝试使用最新的redis:3和redis:2 。
试图将redis
软件包版本一分为二,发现该错误已在2.6.0版本中引入。
测试重现:
const assert = require('assert');
const redis = require('redis').createClient();
const data = JSON.stringify({
"city_name": "Санкт-Петербург" // (russian language)
});
const key = 'somekey';
describe('redis', () => {
before(done => redis.set(key, data, done));
after(done => redis.del(key, done));
for (let i = 0; i < 10000; ++i) {
it(`pass ${i}`, done => {
redis.get(key, (err, results) => {
assert(!err);
assert.strictEqual(results, data);
done();
});
})
}
});
package.json:
{
"devDependencies": {
"mocha": "^2.5.3"
},
"dependencies": {
"redis": "=2.6.0"
}
}
输出:
... (skipped)
✓ pass 1217
✓ pass 1218
1) pass 1219
2) "after all" hook
1219 passing (4s)
2 failing
1) redis pass 1219:
Uncaught AssertionError: '{"city_name":"��анкт-Петербург"}' === '{"city_name":"Санкт-Петербург"}'
+ expected - actual
-{"city_name":"��анкт-Петербург"}
+{"city_name":"Санкт-Петербург"}
失败的通行证号码是浮动的。 Mocha运行时带有-b
标志以在第一次失败时停止,但是如果我们在没有此标志的情况下对其进行测试,则它将在第一次通过失败后继续失败:
... (skipped)
✓ pass 2477
✓ pass 2478
1) pass 2479
2) pass 2480
3) pass 2481
4) pass 2482
5) pass 2483
... (all passes are failed until the end)
第一个失败与数据损坏有关,第二个失败与回调中的err
有关:
{ AbortError: Fatal error encountert. Command aborted. It might have been processed.
at RedisClient.flush_and_error (/Users/silent/Projects/redis-test/node_modules/redis/index.js:350:23)
at JavascriptRedisParser.Parser.returnFatalError (/Users/silent/Projects/redis-test/node_modules/redis/index.js:199:18)
at handleError (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:172:10)
at parseType (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:224:14)
at JavascriptRedisParser.execute (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:404:20)
at Socket.<anonymous> (/Users/silent/Projects/redis-test/node_modules/redis/index.js:267:27)
at emitOne (events.js:96:13)
at Socket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:177:18)
at Socket.Readable.push (_stream_readable.js:135:10)
at TCP.onread (net.js:542:20)
code: 'NR_FATAL',
command: 'GET',
args: [ 'somekey' ],
origin:
ReplyError: Protocol error, got "c" as reply type byte. Please report this.
at parseType (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:224:34)
at JavascriptRedisParser.execute (/Users/silent/Projects/redis-test/node_modules/redis-parser/lib/parser.js:404:20) } undefined
或有时与此:
Uncaught RangeError: out of range index
at RangeError (native)
at concatBuffer (node_modules/redis-parser/lib/parser.js:357:13)
at JavascriptRedisParser.execute (node_modules/redis-parser/lib/parser.js:389:21)
at Socket.<anonymous> (node_modules/redis/index.js:267:27)
at readableAddChunk (_stream_readable.js:177:18)
at Socket.Readable.push (_stream_readable.js:135:10)
at TCP.onread (net.js:542:20)
不能仅使用拉丁字符进行复制。 也无法使用return_buffers: true
复制。
这是通过redis-cli
,也许会有所帮助:
127.0.0.1:6379> get somekey
"{\"city_name\":\"\xd0\xa1\xd0\xb0\xd0\xbd\xd0\xba\xd1\x82-\xd0\x9f\xd0\xb5\xd1\x82\xd0\xb5\xd1\x80\xd0\xb1\xd1\x83\xd1\x80\xd0\xb3\"}"
也可以使用简单字符串Санкт-Петербург
复制,而无需任何JSON.{parse,stringify}
。
127.0.0.1:6379> get somekey
"\xd0\xa1\xd0\xb0\xd0\xbd\xd0\xba\xd1\x82-\xd0\x9f\xd0\xb5\xd1\x82\xd0\xb5\xd1\x80\xd0\xb1\xd1\x83\xd1\x80\xd0\xb3"
@silentroach您当前使用什么解析器版本? 我试图重现此方法,但没有成功。
默认解析器。 这是一个要复制的档案:
npm i && npm t
我当前的节点版本是6.3.0,redis版本是3.2.1( docker run redis
),os x
有趣的是-现在我一直在运行测试(尝试了50次),失败的迭代次数始终是2479、6260、7520
您是否在没有docker的情况下尝试了相同的操作?
嗯,现在尝试过,也无法复制:(
但是可以在生产Redis服务器上进行复制(具有第一次测试迭代),而docker中没有。
将尝试发现差异。
无法在本地Redis上重现,但可以在连接到网络中不同PC的同时重现数据字符串,以复制到更复杂的示例。
(只需将主机替换为与您的IP不同的主机即可通过网络工作)
第一次迭代失败,在接下来的迭代中您会发现out of range index
错误。
我刚刚发布了可解决此问题的新解析器版本。 我很遗憾忘记多字节字符。
现在可以了,谢谢您的快速修复!
感谢您提供的非常好的错误报告! :+1: