错误:失败:无效的线路类型:%s(在位置 %s)使用最新的 npm redis 包版本 4.6 反序列化存储在 redis 7 中的 protobuf 数据

问题描述 投票:0回答:1

我一直在 Node.js 应用程序中使用版本为 3.1.2 的 redis npm 包。现在我正在尝试将 redis npm 包升级到 4.6.13,由于这是一次重大升级,过去适用于 3.1.2 版本的功能在 4.6.13 中已失效。新的redis服务器安装也已升级到最新可用版本7

问题主要出现在我尝试反序列化存储在redis中的protobuf数据时。

我创建了一个示例代码:

我使用的示例代码是:

设置原型消息:


 
 const setApplicationInfo = (data) => {
     try {
        const applicationDetailMessage = new ApplicationDetails();
        applicationDetailMessage.setEmail(data.email);
        applicationDetailMessage.setHomephonenumber('');
        applicationDetailMessage.setMobilephonenumber(data.primaryPhoneNumber);
        applicationDetailMessage.setYearofbirth(data.yearOfBirth);
        applicationDetailMessage.setFirstname(data.firstName);
        applicationDetailMessage.setMiddlename(data.middleName);
        applicationDetailMessage.setLastname(data.lastName);
        applicationDetailMessage.setMonthofbirth(data.monthOfBirth);
        applicationDetailMessage.setDayofbirth(data.dayOfBirth);
        applicationDetailMessage.setSsn(data.ssn);
        applicationDetailMessage.setStreetaddress(data.streetAddress1);
        applicationDetailMessage.setCity(data.city);
        applicationDetailMessage.setState(data.stateCode);
        applicationDetailMessage.setZipcode(data.zipCode);
        applicationDetailMessage.setResidencetype(data.residenceType);
        // applicationDetailMessage.setResidencelengthinyears(data.durationOfResidenceYear);
        // applicationDetailMessage.setResidencelengthinmonths(data.durationOfResidenceMonth);
        const serializedData = applicationDetailMessage.serializeBinary();
        return Buffer.from(serializedData);
     } catch (err) {
         throw new Error(err)
     }
 };

获取redis连接:


 const getRedisConnection  = async () => {
     try {
          const client = await createClient({
               url: `redis://${process.env.REDIS_USER}:${process.env.REDIS_PASS}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`,
            //    legacyMode: true
          })
          client.on('error', err => console.log('Redis Client Error', err))
          await client.connect();
          await client.ping();
          return client;
     } catch (err) {
          throw err;
     }
}

主要函数对原型进行序列化和反序列化



(async () => {
    try {
        const redisConn = await getRedisConnection();
        const id  = '1';
        const data = {
            email: '[email protected]',
            primaryPhoneNumber: '4078790329',
            dayOfBirth: 11,
            monthOfBirth: 12,
            yearOfBirth: 1996,
            firstName: 'Vernon',
            middleName: '',
            lastName: 'McClelland',
            ssn: '228412571',
            streetAddress1: '4311 Grand Avenue',
            city: 'Orlando',
            stateCode: 'FL',
            zipCode: '32810',
            residenceType: 1,
            durationOfResidenceYear: 2,
            durationOfResidenceMonth: 1,
        }
        const message = setApplicationInfo(data)
        const deserializedApplicationObj = ApplicationDetails.deserializeBinary(new Uint8Array(message)).toObject();
        console.log('deserializedApplicationObj', deserializedApplicationObj);
        await redisConn.set(`application_detail_${id}`, message);

        const applicationRes = await redisConn.get(`application_detail_${id}`);
        const applicationBufferData = Buffer.from(applicationRes, 'utf-8');
        console.log('applicationBufferData',  applicationBufferData);
        if (applicationBufferData && applicationBufferData.length > 0) {
            const applicationObj = ApplicationDetails.deserializeBinary(new Uint8Array(applicationBufferData)).toObject();
            console.log('applicationObj', applicationObj);
        }
    } catch (err) {
        throw err;
    }
})()

这工作正常,并且成功反序列化应用程序对象

记录的应用程序对象是:



applicationObj {
  email: '[email protected]',
  homephonenumber: '',
  mobilephonenumber: '4078790329',
  yearofbirth: 32464879,
  firstname: 'Vernon',
  middlename: '',
  lastname: 'McClelland',
  monthofbirth: 12,
  dayofbirth: 11,
  ssn: '228412571',
  streetaddress: '4311 Grand Avenue',
  city: 'Orlando',
  state: 'FL',
  zipcode: '32810',
  residencetype: 1,
  residencelengthinyears: 0,
  residencelengthinmonths: 0
}

现在在函数setApplicationInfo中,当我取消注释以下代码行时:


// applicationDetailMessage.setResidencelengthinyears(data.durationOfResidenceYear);


它抛出错误:

注:

在将序列化的原型缓冲区消息存储到 Redis 服务器之前,我正在检查反序列化是否适用于该特定的原型缓冲区,并且到目前为止它工作正常,



        const deserializedApplicationObj = ApplicationDetails.deserializeBinary(new Uint8Array(message)).toObject();
        console.log('deserializedApplicationObj', deserializedApplicationObj);

当我尝试反序列化从 Redis 服务器获取的数据时,它只会抛出错误

错误信息如下:



 jspb.asserts.fail=function(a,b){for(var c=[],d=1;d<arguments.length;++d)c[d-1]=arguments[d];throw Error("Failure"+(a?": "+a:""),c);};jspb.asserts.assertInstanceof=function(a,b,c,d){for(var e=[],f=3;f<arguments.length;++f)e[f-3]=arguments[f];a instanceof b||jspb.asserts.doAssertFailure("Expected instanceof %s but got %s.",[jspb.asserts.getType(b),jspb.asserts.getType(a)],c,e);return a};
                                                                                                  ^

Error: Failure: Invalid wire type: %s (at position %s)
    at jspb.asserts.fail (protos/node_modules/google-protobuf/google-protobuf.js:90:99)
    at jspb.BinaryReader.nextField (/protos/node_modules/google-protobuf/google-protobuf.js:384:536)
    at proto.demo.entities.application_pb.ApplicationDetails.deserializeBinaryFromReader (protos/build/application_pb.js:24459:17)
    at proto.demo.entities.application_pb.ApplicationDetails.deserializeBinary (protos/build/application_pb.js:24447:66)
    at /del_v2/redis/testredis.js:93:53
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v20.9.0

导致此错误的原因可能是什么?仅当反序列化时存储在 Redis 中的缓冲区数据时才会出现问题。

node.js redis protocol-buffers protobuf.js
1个回答
0
投票

我认为问题与以下几行有关:

const applicationRes = await redisConn.get(`application_detail_${id}`);
const applicationBufferData = Buffer.from(applicationRes, 'utf-8');

第一行返回一个包含二进制数据的字符串。 Node Redis 将对其进行编码,就好像它是转义的 C 样式字符串而不是 UTF-8 一样。

因此,如果该字节是可打印的 ASCII 字符,它将打印它。如果字节类似于换行符或回车符,它将分别返回

\n
\r
。而且,如果该字节没有通用的转义表示形式,它将使用
\x
和十六进制值对其进行转义。因此,包含值 1 的字节将返回
\x01
,包含值 255 的字节将返回
\xff

例如,如果我有字节

74 65 73 74 0A 01 02 03
,我将得到一串
test\n\x01\x02\x03

Buffer.from
接收此文本并错误地对其进行解码,因为它不是正确的 UTF-8。您可能会侥幸逃脱,因为您的数据恰好如此排列。换句话说,这是一个幸运的巧合。如果您更改了数据,这可能会在其他地方发生。如果您在开发过程中没有发现这一点,这将导致很难追踪间歇性错误。所以,确实是一个幸运的巧合! 😉

你需要做的就是告诉 Node Redis 直接返回一个

Buffer
。然后就用那个
Buffer
。您可以通过将
commandOptions
传递给您的呼叫来完成此操作:

const applicationBufferData = await redisConn.get(
  commandOptions({ returnBuffers: true }),
  `application_detail_${id}`
);

这有点笨重,但这将返回一个包含原始字节的

Buffer
,这就是你想要的。

完全披露,我还没有测试过这一点,我可能是错的。但我确实相信这就是正在发生的事情,而且我确实为 Redis 工作,所以我相当了解情况。但是,即使我错了,我希望它至少能提供有用的信息!

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.