快速接入讯飞听见语音听写需绕过sdk,直接用websocket构建通道;先获取appid、apikey、apisecret并配置域名白名单,再生成鉴权签名,建立连接后发送初始化帧,采集麦克风音频转为16khz pcm分块推送,最后解析返回的begin/interim/end状态文本。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

要在Web应用中快速接入讯飞听见语音听写能力,必须绕过官方SDK的冗余封装和浏览器兼容性陷阱,直接基于WebSocket协议构建轻量、可控的语音识别通道。你不需要引入几十KB的SDK,也不必处理Polyfill降级逻辑——现代Chrome/Firefox/Edge(≥v90)原生支持MediaRecorder + WebSocket,整套流程5分钟内可完成调试并看到首条识别文本。
获取合法认证凭证
登录讯飞开放平台,进入「控制台 → 我的应用 → 创建新应用」,服务类型选择【语音听写(流式版)】。创建成功后立即复制三组密钥:APPID、APIKey、APISecret。注意:这三项将在后续签名计算中全部用到,【缺一不可,且大小写敏感】。
在「应用管理 → 域名白名单」中添加你当前开发环境的域名(如localhost:3000、127.0.0.1:5173),未配置将导致WebSocket连接被服务端直接拒绝。
生成符合规范的鉴权签名
讯飞WebSocket连接要求URL携带Authorization头参数,该参数由APIKey、APISecret与GMT时间共同签名生成,不能硬编码或前端拼接明文。
方法一:使用现成工具函数(推荐)
在项目中新建src/utils/xfAuth.js,粘贴以下代码:
export function generateXfAuth(appId, apiKey, apiSecret) {<br> const date = new Date().toGMTString();<br> const signatureOrigin = `host: ws-api.xfyun.cn\n date: ${date}\n GET /v2/iat HTTP/1.1`;<br> const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);<br> const signature = CryptoJS.enc.Base64.stringify(signatureSha);<br> const authorization = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(`api_key="${apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`));<br> return { authorization, date };<br>}
⚠️ 注意:需先通过npm install crypto-js安装依赖,否则签名会失败且无报错提示。
方法二:调用后端代理(更安全)
若项目已有Node.js代理层,在/api/xf-auth接口中完成签名并返回{ authorization, date },前端仅发起一次GET请求即可获取有效凭证,避免密钥泄露风险。
建立WebSocket连接并发送初始化帧
第一步:构造带鉴权参数的WebSocket地址
使用上一步生成的authorization和date,拼接完整URL:
const url = `wss://ws-api.xfyun.cn/v2/iat?${new URLSearchParams({<br> host: 'ws-api.xfyun.cn',<br> date: auth.date,<br> authorization: auth.authorization<br>)}`;
第二步:创建连接并发送首次业务帧
WebSocket打开后,必须立刻发送一个status: 0的初始化帧,否则服务端不会接受后续音频数据:
const ws = new WebSocket(url);<br>ws.onopen = () => {<br> const initFrame = {<br> common: { app_id: appId },<br> business: {<br> language: 'zh_cn',<br> domain: 'iat',<br> accent: 'mandarin',<br> engine_type: 'sms16k'<br> },<br> data: { status: 0, format: 'audio/L16;rate=16000', encoding: 'raw' }<br> };<br> ws.send(JSON.stringify(initFrame));<br>};
采集麦克风音频并分块推送
① 请求用户授权并启动MediaRecorder:navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {<br> mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm', audioBitsPerSecond: 16000 });<br>});
② 监听dataavailable事件,提取原始PCM数据:
WebM容器自带封装开销,讯飞要求纯L16裸数据。必须用AudioContext解码再重采样为16kHz线性PCM——这是最容易卡住的环节,跳过会导致服务端静默丢弃所有帧。
③ 每160ms触发一次音频切片,按512字节分块发送:
服务端对单次ws.send()的数据长度有硬限制,超过则断连。需手动切割ArrayBuffer,并为每块添加status: 2的中间帧头:
const chunk = audioBuffer.slice(i, i + 512);<br>const frame = {<br> data: {<br> status: 2,<br> format: 'audio/L16;rate=16000',<br> encoding: 'raw',<br> audio: btoa(String.fromCharCode(...new Uint8Array(chunk)))<br> }<br>};<br>ws.send(JSON.stringify(frame));
接收并解析识别结果
讯飞返回的JSON消息体中,data.result.text字段即为当前增量文本。但要注意状态标识:
• status: "BEGIN" 表示开始识别,可清空历史文本;
• status: "INTERIM" 是中间结果,适合实时追加显示;
• status: "END" 标志本次语音结束,应锁定最终文本并关闭连接。
关键逻辑示例:ws.onmessage = (event) => {<br> const res = JSON.parse(event.data);<br> if (res.code !== 0) throw new Error(res.message);<br> if (res.data?.result?.status === 'END') {<br> console.log('最终结果:', res.data.result.text);<br> } else if (res.data?.result?.text) {<br> console.log('实时结果:', res.data.result.text);<br> }<br>};
最后一步:语音结束后调用mediaRecorder.stop()释放麦克风,调用ws.close()终止连接。不要遗漏,否则用户下次点击无法重新获取音频流。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!







