WebUSB API 允许网页在安全前提下直接与原始 USB 设备异步通信,需设备嵌入特定平台能力描述符且浏览器端严格按 open→selectConfiguration→claimInterface 顺序操作,再通过 controlTransferOut 和 transferIn 收发数据,并做好断连监听与异常兜底。

WebUSB API 允许网页在安全前提下,直接与原始 USB 设备(如自定义固件的 Arduino、传感器模块、工业控制器等)进行异步数据交互,无需驱动安装。关键在于绕过 HID 或大容量存储等通用类协议,走底层 USB 传输通道。
设备端需显式声明 WebUSB 支持
原始设备必须在 USB 描述符中嵌入 WebUSB 平台能力描述符(Platform Capability Descriptor),否则浏览器不会将其识别为可被 WebUSB 访问的设备。该描述符包含固定 UUID {3408b638-09a9-47a0-8bfd-a0768815b665} 和指定的 landing page URL 索引。仅靠 Vendor ID / Product ID 匹配不够——若设备未声明,navigator.usb.requestDevice() 即使过滤匹配也不会列出它。
常见实现方式:
- 使用支持 WebUSB 的 MCU SDK(如 Arduino Core for Nano 33 BLE、ESP32-S2/S3 的 TinyUSB 栈)启用 WebUSB CDC 或自定义类接口
- 在固件中手动构造并注入平台描述符(需熟悉 USB 描述符结构和设备枚举流程)
- 验证方法:插入设备后访问
chrome://device-log?refresh=1,搜索 “WebUSB” 或查看平台描述符字段是否完整
浏览器端连接与接口声明是异步协作前提
用户点击触发后,必须严格按顺序完成异步操作链,每一步都返回 Promise,不可跳过或乱序:
-
await device.open():建立底层连接,初始化设备状态 -
await device.selectConfiguration(1):选择有效配置(多数单配置设备用 1) -
await device.claimInterface(0):声明对 interface 0 的独占控制权(若设备含多个接口,需分别 claim)
⚠️ 若未 claim 接口就调用 transferIn/transferOut,会直接抛出 NotFoundError。claim 后接口即被当前页面“锁定”,其他标签页或应用无法同时访问同一接口。
用 controlTransferOut / transferIn 实现原始命令收发
对于无标准 CDC 类的原始设备,推荐优先使用控制传输(control transfer)发送命令,再用中断或批量端点接收响应,因其开销小、兼容性高:
- 发送指令:
device.controlTransferOut({ requestType: 'vendor', recipient: 'device', request: 0x01, value: 0x00, index: 0x00 }, data)—— 其中request是你固件约定的命令码,data是任意ArrayBuffer或Uint8Array - 接收响应:
const result = await device.transferIn(1, 64)—— 假设端点 1(IN 方向)已配置为中断输入,最大读取 64 字节;返回result.data是DataView,可用new TextDecoder().decode()转字符串 - 注意:端点号(endpoint number)须与设备描述符中定义的一致,且方向位(bit 7)已由
transferIn/transferOut隐含处理,传入数字时只需低 7 位(如端点地址 0x81 → 传 1)
保持连接稳定与异常兜底
原始设备可能复位、断连或响应超时,需主动监听并恢复:
- 监听断连:
device.addEventListener('disconnect', () => console.log('设备已拔出')) - 避免 Promise 悬停:所有
await操作必须包裹try/catch,尤其transferIn可能因设备无响应而长期挂起,建议用AbortController设置超时 - 释放资源:操作完成后调用
device.close();若页面卸载前未 close,系统可能保留接口占用,导致下次 claim 失败

















