SvelteKit中如何返回ReadableStream作为响应?ytdl-core使用遇阻
解决SvelteKit中ytdl-core音频流无法作为响应返回的问题
问题根源
- SvelteKit的API端点必须返回Response对象,直接返回
read()结果或原始ReadableStream不符合框架要求,这是报错的直接原因。 - 调用
stream.read()的方式错误:该方法仅读取流的单个数据块,读完后返回null,并非返回完整音频流。
修正步骤与代码
1. 修复youtube函数的参数与逻辑
修正参数不匹配问题,同时添加音频过滤确保仅获取音频流:
import { downloadFromInfo, getInfo, validateID } from 'ytdl-core' async function youtube(id: string) { if (!validateID(id)) throw new Error("视频ID无效") const info = await getInfo(`https://youtu.be/${id}`) // 过滤仅音频格式,避免获取视频流 return downloadFromInfo(info, { filter: 'audioonly' }) }
2. 修正API路由代码(SvelteKit +server.ts)
将Node.js的ReadableStream转换为Web标准流,构造合法的Response返回:
import type { RequestHandler } from './$types' import { youtube } from '$lib/youtube' export const GET: RequestHandler = async ({ params }) => { try { const { id } = params const nodeStream = await youtube(id) // 将Node.js流转换为Web标准流,适配Response要求 const webStream = new ReadableStream({ start(controller) { nodeStream.on('data', chunk => controller.enqueue(chunk)) nodeStream.on('end', () => controller.close()) nodeStream.on('error', err => controller.error(err)) } }) // 返回合法Response对象,设置音频响应头 return new Response(webStream, { headers: { 'Content-Type': 'audio/mpeg', 'Content-Disposition': 'inline; filename="youtube-audio.mp3"' } }) } catch (err) { return new Response((err as Error).message, { status: 400 }) } }
关键说明
- Response规则:SvelteKit API路由强制要求返回Response实例,这是框架核心规则。
- 流格式兼容:Node.js ReadableStream与Web标准ReadableStream不兼容,必须手动转换才能用于Response。
- 响应头作用:
Content-Type告知浏览器这是音频文件;Content-Disposition设为inline可让浏览器直接播放,改为attachment则触发下载。
内容的提问来源于stack exchange,提问作者mavdotjs
相关产品推荐
相关产品推荐

