You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

USB读卡器读取时报TypeError [ERR_INVALID_ARG_TYPE]错误求助

USB读卡器读取数据报错:TypeError [ERR_INVALID_ARG_TYPE]

读卡器已成功连接,但执行读取功能时抛出错误:

TypeError [ERR_INVALID_ARG_TYPE]: The "size" argument must be of type number. Received an instance of Buffer

问题代码片段

const express = require('express');
const usb = require('usb');
const cors = require('cors');
const app = express();
const port = 3001;

app.use(cors());
app.use(express.json());

// 列出所有可用USB设备的函数
function listUSBDevices() {
  const devices = usb.getDeviceList();
  // 返回USB设备列表
  return devices.map((device, index) => ({
    id: index + 1,
    descriptor: device.deviceDescriptor,
    manufacturer: device.deviceDescriptor.iManufacturer,
    product: device.deviceDescriptor.iProduct,
  }));
}

// 连接指定USB设备的函数
function connectToUSBDevice(targetVendorId, targetProductId) {
  const devices = usb.getDeviceList();
  const targetDevice = devices.find((device) => {
    return (
      device.deviceDescriptor.idVendor === targetVendorId &&
      device.deviceDescriptor.idProduct === targetProductId
    );
  });

  return targetDevice;
}

// 从USB设备读取数据的函数
function readDataFromUSBDevice(vendorId, productId, blockNum, callback) {
  const targetDevice = connectToUSBDevice(vendorId, productId);

  if (!targetDevice) {
    callback('USB device not found.');
    return;
  }

  try {
    targetDevice.open();

    const interface = targetDevice.interfaces[0];
    const endpoint = interface.endpoints[0];

    const bufferSize = 64; // 设置缓冲区大小(单位:字节)
    const buffer = Buffer.alloc(bufferSize); // 创建用于存储读取数据的缓冲区

    // 发送读取命令(请根据设备协议修改此部分)
    buffer[0] = 0x04;
    buffer[1] = 0x21;
    buffer[2] = 0x02;
    buffer[3] = blockNum; // 替换为目标块编号
    // 根据协议对缓冲区进行其他必要修改

    endpoint.transfer(buffer, (error, actualLength) => {
      if (error) {
        console.error('Error sending command to USB device:', error);
        targetDevice.close();
        callback('Error reading from USB device.');
      } else {
        // 处理接收的数据并传递给回调函数
        const data = buffer.slice(0, actualLength).toString('utf8');
        targetDevice.close();
        callback(null, data);
      }
    });
  } catch (error) {
    console.error('Error reading from USB device:', error);
    callback('Error reading from USB device.');
  }
}


// 处理根URL请求
app.get('/', (req, res) => {
  res.send('Hello, this is your server response!');
});

app.get('/listUSBDevices', (req, res) => {
  const usbDevices = listUSBDevices();
  res.json(usbDevices);
});

// 添加读取数据的新路由
app.post('/communicateWithDevice', (req, res) => {
  const { vendorId, productId, action, data, blockNum } = req.body;

  if (action === 'read') {
    readDataFromUSBDevice(vendorId, productId, blockNum, (error, result) => {
      if (error) {
        res.json({ message: error });
      } else {
        res.json({ message: result });
      }
    });
  } else if (action === 'write') {
    const result = writeToUSBDevice(targetDevice, data);
    res.json({ message: result });
  } else if (action === 'connectToDevice') { // 修正动作名称
    const targetDevice = connectToUSBDevice(vendorId, productId);
    const result = targetDevice ? 'Connected to USB device successfully.' : 'USB device not found.';
    res.json({ message: result });
  } else {
    res.json({ message: 'Invalid action specified.' });
  }
});


app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

错误原因

node-usb库中,端点的transfer方法参数根据端点类型不同而不同:

  • OUT端点(用于向设备发送数据):第一个参数是要发送的Buffer
  • IN端点(用于从设备读取数据):第一个参数是读取的字节数(数字)

你的代码直接使用了interface.endpoints[0],如果该端点是IN类型,传入Buffer就会触发类型错误。此外,读取读卡器数据通常需要先通过OUT端点发送读取命令,再通过IN端点接收返回数据。

解决方案

  1. 区分IN/OUT端点,分别用于读取和发送命令
  2. 先发送读取命令,再读取设备返回的数据
  3. 修复端点调用逻辑,添加接口权限管理

修正后的核心代码

// 从USB设备读取数据的函数
function readDataFromUSBDevice(vendorId, productId, blockNum, callback) {
  const targetDevice = connectToUSBDevice(vendorId, productId);

  if (!targetDevice) {
    callback('USB device not found.');
    return;
  }

  try {
    targetDevice.open();
    const interface = targetDevice.interfaces[0];

    // 处理内核驱动,申请接口权限
    if (interface.isKernelDriverActive()) {
      interface.detachKernelDriver();
    }
    interface.claim();

    // 分别找到OUT(发命令)和IN(读数据)端点
    const outEndpoint = interface.endpoints.find(ep => ep.direction === 'out');
    const inEndpoint = interface.endpoints.find(ep => ep.direction === 'in');

    if (!outEndpoint || !inEndpoint) {
      callback('Required endpoints not found.');
      targetDevice.close();
      return;
    }

    // 构造读取命令缓冲区
    const cmdBuffer = Buffer.alloc(64);
    cmdBuffer[0] = 0x04;
    cmdBuffer[1] = 0x21;
    cmdBuffer[2] = 0x02;
    cmdBuffer[3] = blockNum;

    // 第一步:发送读取命令到设备
    outEndpoint.transfer(cmdBuffer, (cmdError) => {
      if (cmdError) {
        console.error('Error sending command:', cmdError);
        interface.release();
        targetDevice.close();
        callback('Failed to send read command.');
        return;
      }

      // 第二步:从IN端点读取设备返回的数据
      const readSize = 64;
      inEndpoint.transfer(readSize, (readError, data) => {
        // 释放资源
        interface.release();
        targetDevice.close();
        
        if (readError) {
          console.error('Error reading data:', readError);
          callback('Failed to read data from device.');
          return;
        }
        
        // 处理并返回数据
        const result = data.toString('utf8');
        callback(null, result);
      });
    });
  } catch (error) {
    console.error('Error during USB operation:', error);
    targetDevice?.close();
    callback('Error reading from USB device.');
  }
}

额外注意:

  • 命令格式需严格遵循你的读卡器通信协议,上述命令仅为示例
  • 操作完成后必须释放接口权限并关闭设备,避免资源泄漏

内容的提问来源于stack exchange,提问作者Radhika Padiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:15:53