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

SvelteKit通过HTTP响应播放音频文件报错排查与解决

问题

使用AWS Polly文本转语音API,尝试将音频响应返回给客户端播放时,持续遇到以下错误:

GET blob:http://localhost:5173/8788f478-32ef-4e76-80a1-93c4f1a6a3a8 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE
localhost/:1 Uncaught (in promise) DOMException: Failed to load because no supported source was found.

生成的音频写入磁盘可以正常播放,但通过Response返回给客户端就无法播放,相关代码如下:

客户端代码(+page.svelte)

<script lang="ts">
  let audio: any;

  const handleClick = async () => {
    const what = await fetch('/api/speech', {
      method: 'POST',
      headers: {
        'Content-Type': 'audio/mpeg'
      }
    });

    /**
     * Play audio from blob
     */
    const blob = await what.blob();
    const url = URL.createObjectURL(blob);

    audio.src = url;
    audio.play();
  };
</script>

<button on:click={handleClick}> Clicky </button>

<audio bind:this={audio}>
  <source class="track" src="" type="audio/mpeg" />
</audio>

服务端代码(routes/api/speech/+server.ts)

import AWS from 'aws-sdk';

export const POST = async () => {
  const awsConfig = new AWS.Config(...);

  const polly = new AWS.Polly(awsConfig);

  const input = {
    Engine: 'standard',
    LanguageCode: 'en-US',
    OutputFormat: 'mp3',
    TextType: 'text',
    VoiceId: 'Ivy',
    Text: `hello hello`
  };

  const speech = (await polly.synthesizeSpeech(input, (err, data: any) => {

    if (err) {
      new Response(String('err'));
    }

    /**
     * Return data in a way that's consumable by the browser
     */
    if (data) {
      if (data.AudioStream instanceof Buffer) {
        // fs.writeFile('speech.mp3', data.AudioStream, function (err) {
        //   if (err) {
        //     return console.log(err);
        //   }
        //   console.log('The file was saved!');
        // });
        return data;
      }
    }
  })) as any;

  return new Response(speech.AudioStream, {
    headers: {
      'Content-Type': 'audio/mpeg'
    }
  });
};
解决方法

问题集中在三个关键点,逐一修复即可解决:

1. 错误混用AWS SDK的回调与Promise模式

polly.synthesizeSpeech使用await时,不需要传入回调函数——回调内的返回值不会被await捕获,你拿到的speech其实是SDK的请求对象,而非实际音频数据。

修改服务端调用逻辑,改用纯Promise模式:

// 移除回调,直接通过promise()获取结果
const speech = await polly.synthesizeSpeech(input).promise();

2. 客户端请求头设置错误

你在POST请求中设置了Content-Type: audio/mpeg,但实际并未发送任何音频数据,这个头是多余的,还可能导致服务端误解请求格式。直接移除该请求头即可。

修复客户端fetch请求:

const what = await fetch('/api/speech', {
  method: 'POST'
  // 移除错误的Content-Type头
});

3. 响应缺少Content-Length头

浏览器播放音频时需要知晓文件大小,否则会触发范围请求(Range)错误。返回Response时,添加Content-Length头,值为音频Buffer的长度:

修复服务端Response部分:

return new Response(speech.AudioStream, {
  headers: {
    'Content-Type': 'audio/mpeg',
    'Content-Length': speech.AudioStream.length.toString()
  }
});

额外优化:清理Blob URL

播放完成后释放Blob URL,避免内存泄漏:

audio.addEventListener('ended', () => {
  URL.revokeObjectURL(audio.src);
});

内容的提问来源于stack exchange,提问作者Kyle Truong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 15:25:32