背景:前端UI上有两个按钮【试听】【停止】,要求点击试听的时候播放音频,点击停止的时候停止播放,后端返回的.wav字节流
实现:拉取二进制Blob播放
const audioPlayer = ref(null)
const audioObjectUrl = ref('')
const handlePreview = async () => {
try {
const res = await apis.system.getVoicePreview({
voiceSpeed: speed.value,
voiceType: AudioTypeShort[audioType.value],
})
if (!audioPlayer.value) {
audioPlayer.value = new Audio()
}
if (audioObjectUrl.value) {
URL.revokeObjectURL(audioObjectUrl.value)
audioObjectUrl.value = ''
}
let audioBlob = res?.data
if (audioBlob instanceof ArrayBuffer) {
audioBlob = new Blob([audioBlob], { type: 'audio/wav' })
}
if (!audioBlob || !(audioBlob instanceof Blob)) {
console.error('获取音频失败: 响应不是音频 Blob')
return
}
audioObjectUrl.value = URL.createObjectURL(audioBlob)
audioPlayer.value.src = audioObjectUrl.value
audioPlayer.value.currentTime = 0
await audioPlayer.value.play()
} catch (error) {
console.error('试听失败:', error)
}
}
const handleStop = () => {
if (!audioPlayer.value) return
audioPlayer.value.pause()
audioPlayer.value.currentTime = 0
if (audioObjectUrl.value) {
URL.revokeObjectURL(audioObjectUrl.value)
audioObjectUrl.value = ''
}
}
onBeforeUnmount(() => {
if (!audioPlayer.value) return
audioPlayer.value.pause()
audioPlayer.value.src = ''
audioPlayer.value = null
if (audioObjectUrl.value) {
URL.revokeObjectURL(audioObjectUrl.value)
audioObjectUrl.value = ''
}
})
播放音频的方案一般有:
- 直接URL播放:后端返回可访问音频URL,前端用或Audio对象控制play()/pause()/currentTime=0.
- 拉取二进制Blob播放:前端用fetch拿到音频二进制,URL.createObjectURL(blob)生成本地URL再播放。
- Range分段流式播放:后端支持Range请求,前端只请求需要的片段,适合大文件/首播快
- MediaSource流式拼接:前端使用MediaSource动态喂数据,适合长音频或自定义流式控制。
- WebSocket/实时流:用于实时生成语音(TTS)或直播式音频
- 短音频、权限简单:优先用“直接 URL 播放”。
- 需要鉴权/防盗链:用“Blob 播放”或“签名 URL”。
- 大文件/首播慢:用“Range”或 “HLS”。
- 实时语音/TTS:用 “WebSocket + MediaSource”。