把浏览器的语音识别能力接到Node.js服务端,核心思路不是让Node.js去调用某个语音SDK,而是用WebSpeech API在客户端完成听写,再通过WebSocket把文字流实时推送到Node.js进行处理。这种做法省去了自行部署ASR模型的算力成本,也避开了浏览器之外难以直接调用麦克风的限制。实际项目中,前端负责采集和识别,Node.js负责接收、持久化和广播,两者分工清晰。

WebSpeech API的客户端识别机制
WebSpeech API中的SpeechRecognition接口由浏览器实现,Chrome和Edge基于系统语音引擎提供识别能力。在页面中需要先检测window.SpeechRecognition或window.webkitSpeechRecognition是否存在,然后创建实例。设置continuous为true可让识别持续进行,interimResults为true能返回临时结果,方便做实时字幕。
识别对象启动后,麦克风权限会被请求。用户授权后,onresult事件会周期性触发,事件对象的results是一个类数组结构,每个结果项包含transcript文本和isFinal标记。临时结果可用于前端即时渲染,最终结果才应推送到Node.js存储,避免重复写入。
下面是一个最小可用的前端识别代码片段,展示了如何把识别结果通过WebSocket发走:
// 前端浏览器环境代码
const ws = new WebSocket('ws://127.0.0.1:3000');
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SR();
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = 'zh-CN';
recognition.onresult = function(event) {
for (let i = event.resultIndex; i < event.results.length; i++) {
const result = event.results[i];
const text = result[0].transcript;
// 仅发送最终结果给Node.js
if (result.isFinal) {
ws.send(JSON.stringify({ type: 'final', text: text }));
}
}
};
recognition.start();
Node.js端的WebSocket接收服务
Node.js本身不处理语音,它只作为一个中转和存储节点。使用ws库可以很快搭建一个WebSocket服务,监听客户端连接并接收JSON消息。收到final类型消息后,可将其追加写入文本文件,或存入数据库,或通过另一个WebSocket广播给监听页面,实现多端同步字幕。
需要注意,浏览器可能在网络抖动时断开重连,Node.js服务应维护每个连接的会话标识,避免文字错乱。简单方案是在前端连接时发送一个roomId,服务端按房间隔离消息。以下代码演示了基础的服务端接收与落盘逻辑:
// Node.js服务端代码
const WebSocket = require('ws');
const fs = require('fs');
const wss = new WebSocket.Server({ port: 3000 });
const fileStream = fs.createWriteStream('./transcript.txt', { flags: 'a' });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
let data;
try {
data = JSON.parse(message);
} catch (e) {
return;
}
if (data.type === 'final') {
const line = '[' + new Date().toISOString() + '] ' + data.text + 'n';
fileStream.write(line);
// 可在此处广播给其它客户端
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(line);
}
});
}
});
});
console.log('WebSocket server on ws://127.0.0.1:3000');
上述实现中,文件写入是追加模式,适合长时间会议记录。如果业务要求高并发,建议改为批量写入或引入消息队列。同时,服务端不应信任前端发来的任何字段,生产环境需做长度校验和敏感词过滤。
常见故障与优化方向
很多人在联调时发现Node.js收不到消息,多半是前端WebSocket地址写错,或者浏览器禁止非HTTPS页面使用麦克风。本地开发可用127.0.0.1免证书,但部署到公网必须上HTTPS,否则getUserMedia和SpeechRecognition都会被禁用。另一个坑是Chrome的识别在标签页后台时会暂停,需提醒用户保持页面活跃。
在准确性方面,WebSpeech API依赖浏览器内置模型,无法针对专业术语微调。若业务场景有大量行话,可在Node.js端做后置替换,比如把音近词映射到标准术语表。也可以将前端临时结果缓存,当最终结果返回时用编辑距离算法做平滑处理,减少闪烁。
性能上,单台Node.js服务可支撑数千长连接,但文字广播会随客户端增多而放大CPU占用。此时应引入Redis的发布订阅,让Node.js实例无状态横向扩展。以下示例展示用ioredis解耦接收与广播:
// Node.js结合Redis发布订阅
const WebSocket = require('ws');
const Redis = require('ioredis');
const sub = new Redis();
const pub = new Redis();
const wss = new WebSocket.Server({ port: 3000 });
sub.subscribe('transcript_channel');
sub.on('message', function(channel, message) {
wss.clients.forEach(function(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
wss.on('connection', function(ws) {
ws.on('message', function(msg) {
const data = JSON.parse(msg);
if (data.type === 'final') {
pub.publish('transcript_channel', data.text);
}
});
});
整体来看,Node.js与WebSpeech API的集成属于轻量级实时语音方案,开发成本低,适合原型和中低并发产品。若日后需要离线或更高精度,可平滑替换为服务端ASR,而现有的WebSocket传输层几乎不用改动。
Node.jsWebSpeech_APIreal_time_speech_to_text修改时间:2026-08-17 13:04:17