node-opcua调用valueRank>1数组参数方法报BadInvalidArgument
问题描述
- 基于Node.js使用node-opcua搭建OPC UA服务器时,注册了输入参数为二维数组的方法。
- 使用UaExpert等客户端浏览服务器时,方法参数描述显示正常,也支持在客户端侧设置参数值,但调用方法时直接返回
BadInvalidArgument异常。 - 将数组维度修改为1(即设置
valueRank为1)时,方法可正常运行。 - 参考官方server-methods最小示例编写的代码如下:
const { OPCUAServer, DataType, Variant,VariantArrayType, StatusCodes, makeAccessLevelFlag } = require("node-opcua"); (async () => { try { const server = new OPCUAServer({ port: 4334 // 服务端监听套接字端口 }); await server.initialize(); const addressSpace = server.engine.addressSpace; const namespace = addressSpace.getOwnNamespace(); const myDevice = namespace.addObject({ organizedBy: addressSpace.rootFolder.objects, browseName: "MyDevice" }); // 在设备对象上添加方法 const method = namespace.addMethod(myDevice,{ browseName: "Bark", inputArguments: [ { name:"nbBarks", description: { text: "指定需要触发的bark次数" }, dataType: DataType.Int32, valueRank: 2, arrayDimensions: [2, 2] } ], outputArguments: [{ name:"Barks", description:{ text: "生成的bark结果" }, dataType: DataType.UInt32, valueRank: -1 }] }); // 绑定方法实际处理逻辑 method.bindMethod((inputArguments,context,callback) => { const callMethodResult = { statusCode: StatusCodes.Good, outputArguments: [{ dataType: DataType.String, arrayType: VariantArrayType.Array, value :99 }] }; callback(null,callMethodResult); }); await server.start(); console.log("服务已启动,按CTRL+C停止"); const endpointUrl = server.endpoints[0].endpointDescriptions()[0].endpointUrl; console.log("主服务端点地址:", endpointUrl ); } catch(err) { console.log(err); } })();
- UaExpert中调用方法前的界面截图:

- 客户端已正确识别该参数为维度[2x2]的数组,但调用时仍触发
BadInvalidArgument异常。
故障原因
问题由两处配置错误导致:
- 多维数组类型未显式声明:OPC UA规范中,一维数组对应
VariantArrayType.Array类型,二维及以上维度的数组统一为VariantArrayType.Matrix类型。当valueRank设置为大于1的值时,node-opcua要求必须显式指定arrayType为Matrix,仅靠valueRank和arrayDimensions参数无法让服务端正确识别多维数组格式,参数校验阶段会直接判定入参不合法,返回BadInvalidArgument。 - 输出参数配置不匹配:代码中定义的输出参数
Barks数据类型为UInt32,但实际方法绑定逻辑中返回的输出参数类型写为String,传入的值99也和字符串类型不匹配,即使入参问题修复,该错误也会导致调用失败。
修正方案
修改两处配置即可解决问题:
- 在二维输入参数的定义中,补充
arrayType: VariantArrayType.Matrix声明 - 修正输出参数的类型、arrayType配置,和预先定义的输出参数规则保持一致
修正后的核心代码片段:
// 方法定义部分 const method = namespace.addMethod(myDevice,{ browseName: "Bark", inputArguments: [ { name:"nbBarks", description: { text: "指定需要触发的bark次数" }, dataType: DataType.Int32, valueRank: 2, arrayDimensions: [2, 2], arrayType: VariantArrayType.Matrix // 补充多维数组类型声明 } ], outputArguments: [{ name:"Barks", description:{ text: "生成的bark结果" }, dataType: DataType.UInt32, valueRank: -1, arrayType: VariantArrayType.Scalar // 标量返回值显式声明类型 }] }); // 方法绑定逻辑部分 method.bindMethod((inputArguments,context,callback) => { // 可开启打印验证接收到的二维数组格式 // console.log("接收入参:", inputArguments[0].value); const callMethodResult = { statusCode: StatusCodes.Good, outputArguments: [{ dataType: DataType.UInt32, // 和定义的输出类型保持一致 arrayType: VariantArrayType.Scalar, value :99 }] }; callback(null,callMethodResult); });
修改后重启服务,传入符合[2,2]维度要求的Int32二维数组调用方法,即可正常返回结果,不会再抛出BadInvalidArgument异常。
内容的提问来源于stack exchange,提问作者erg
相关产品推荐
相关产品推荐

