【问题标题】:Why redis returns a [239, 191, 189] response buffer?为什么 redis 返回一个 [239, 191, 189] 响应缓冲区?
【发布时间】:2017-05-11 14:18:39
【问题描述】:

我正在使用 redis 存储位域数据,并在每个偏移量上设置一个 u4 值。
我需要在 Nodejs 服务器中获取缓冲区。
对于 0-7,redis 返回正确的缓冲区。
但是当设置 8-15 值时,它会返回一个奇怪的缓冲区。Uint8Array 视图进入缓冲区并显示 [239,191,189] 表示乱码。 这是复制运行的测试代码。
顺便说一句,响应缓冲区出现问题。尝试获取 #0 值是可以的。

const http = require('http');
const url = require('url');
const fs = require('fs');
const redis = require('redis'),
      RDS_PORT = 6379,
      RDS_HOST = '139.199.33.69',//139.199.33.69
      RDS_OPTS = {detect_buffers: true},
      client = redis.createClient(RDS_PORT, RDS_HOST, RDS_OPTS);
console.log('redis ready')
const canvas_name = 'canvas-bitfield';
client.del(canvas_name)
client.send_command("bitfield",[canvas_name,'SET','u4','#0',10,'OVERFLOW','FAIL'])

client.send_command('bitfield',[canvas_name,'GET','u4',0],redis.print) //reply:10

client.get(canvas_name,function(err, reply){
    if(err){console.log(err)}
    const buff = Buffer.from(reply.toString());
    const view8 = new Uint8Array(buff); 
    console.log(view8) //Uint8Array(3) [239, 191, 189]
})

【问题讨论】:

  • 这无关,但我还是要指出:send_command 是异步。因此,您应该使用回调参数来确保在 send_command 真正完成后执行任何后续命令:client.send_command(command, args, callback)

标签: javascript node.js redis


【解决方案1】:

为什么redis返回一个[239,191,189]的响应缓冲区?

请注意,replyString 而不是 Buffer为什么?你使用的是detect_buffers: true。在redis 包的文档中,当此选项设置为true 时,reply 的类型取决于传递给client.get() 的第一个参数的类型。既然你给它传递了一个Stringcanvas_name是一个String),那么reply的值也是一个String

client.get(canvas_name,function(err, reply){
    console.log(typeof reply) // => String
    // ...

为此,redisinternally 调用:Buffer.toString()<Buffer a0> 的缓冲区转换为字符串,然后将此字符串传递给回调;绑定到reply。问题是Buffer.toString(),没有传递任何参数,将尝试使用 UTF-8 解码缓冲区,但<Buffer a0> 不是有效的 UTF-8 字符串! Node.js 在这种情况下 silently fails 并返回 U+FFFD 替换字符。因此reply 是一个字符串,只包含一个字符 U+FFFD 或 65533。

client.get(canvas_name,function(err, reply){
    console.log(reply.length); // 1
    console.log(reply.charCodeAt(0)) // => 65533
    // ...

这个数字 (65533) 来自 redis (Node.js) 未能将您的缓冲区解析为 UTF-8 字符串!从那里,您将 65533 放入一个 Buffer 并创建一个 Uint8Array,[239, 191, 189]

console.log(Buffer.from("\uFFFD")) // => <Buffer ef bf bd>
console.log(new Uint8Array(Buffer.from("\uFFFD"))); // => Uint8Array(3) [239, 191, 189] 

要快速解决您的问题,您需要告诉redis 包不要转换 缓冲区到一个字符串。而是直接获取缓冲区:

client.get(new Buffer(canvas_name), function(err, reply) {
    console.log(typeof reply) // => Buffer
    console.log(reply) // => <Buffer a0>
    if(err){console.log(err)}
    const view8 = new Uint8Array(reply);
    console.log(view8) // => Uint8Array(3) [160]
});

注意:十进制值在 0-7 范围内的缓冲区将成功解码为 UTF-8 字符串,这就是为什么您碰巧得到了正确的缓冲区。

【讨论】:

  • 谢谢!我终于用 redis 的 {return_buffers:true} 选项解决了这个问题。
  • 太棒了!如果你觉得它有用,请接受这个答案。
猜你喜欢
  • 2014-12-03
  • 2013-06-17
  • 2021-04-02
  • 1970-01-01
  • 2022-11-28
  • 2018-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多