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

开发网站版YouTube视频下载器:如何调出文件保存对话框?

网站版YouTube视频下载器触发保存对话框解决方案

ytdl-core是Node.js端的视频处理库,本身不具备触发浏览器保存对话框的能力——这个功能需要前端API配合实现。下面提供两种可行方案:

一、前后端结合方案(推荐,无跨域问题)

1. 后端接口实现(Node.js + Express)

用ytdl-core处理视频流,通过接口返回给前端,并设置正确的响应头:

const express = require('express');
const ytdl = require('ytdl-core');
const app = express();

// 处理跨域(如果前端和后端域名不同)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET');
  next();
});

app.get('/download', async (req, res) => {
  const videoUrl = req.query.url;
  if (!ytdl.validateURL(videoUrl)) {
    return res.status(400).send('无效的YouTube链接');
  }

  const videoInfo = await ytdl.getInfo(videoUrl);
  // 选择最高画质的视频格式
  const targetFormat = ytdl.chooseFormat(videoInfo.formats, { quality: 'highest' });

  // 设置响应头,告知浏览器这是可下载文件
  res.setHeader(
    'Content-Disposition',
    `attachment; filename="${videoInfo.videoDetails.title.replace(/[<>:"/\\|?*]/g, '')}.${targetFormat.container}"`
  );
  res.setHeader('Content-Type', targetFormat.mimeType);

  // 将视频流管道到响应
  ytdl(videoUrl, { format: targetFormat }).pipe(res);
});

app.listen(3000, () => console.log('后端服务运行在3000端口'));

2. 前端触发下载逻辑

通过fetch请求后端接口,接收Blob数据后,用<a>标签触发浏览器的保存对话框:

// 绑定到按钮点击事件(必须由用户主动触发,否则浏览器会阻止)
document.getElementById('downloadBtn').addEventListener('click', async () => {
  const youtubeUrl = document.getElementById('videoUrlInput').value;
  if (!youtubeUrl) {
    alert('请输入YouTube视频链接');
    return;
  }

  try {
    const response = await fetch(`http://localhost:3000/download?url=${encodeURIComponent(youtubeUrl)}`);
    if (!response.ok) throw new Error('下载请求失败');

    const videoBlob = await response.blob();
    const blobUrl = URL.createObjectURL(videoBlob);

    // 创建临时a标签触发下载
    const downloadLink = document.createElement('a');
    downloadLink.href = blobUrl;
    // 从后端响应头获取文件名,或自定义
    const filename = response.headers.get('Content-Disposition').match(/filename="(.*)"/)[1];
    downloadLink.download = filename;
    
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
    
    URL.revokeObjectURL(blobUrl); // 释放内存资源
  } catch (err) {
    console.error(err);
    alert('下载失败,请检查链接是否有效');
  }
});

二、纯前端尝试方案(存在跨域风险)

由于浏览器CORS政策限制,直接在前端调用ytdl-core大概率会触发跨域错误,仅作参考:

// 需先通过browserify/webpack将ytdl-core打包为前端可用模块
async function downloadVideoFrontend(youtubeUrl) {
  try {
    const videoInfo = await ytdl.getInfo(youtubeUrl);
    const targetFormat = ytdl.chooseFormat(videoInfo.formats, { quality: 'highest' });

    // 直接请求视频链接可能触发CORS错误
    const response = await fetch(targetFormat.url);
    const videoBlob = await response.blob();
    const blobUrl = URL.createObjectURL(videoBlob);

    const downloadLink = document.createElement('a');
    downloadLink.href = blobUrl;
    downloadLink.download = `${videoInfo.videoDetails.title.replace(/[<>:"/\\|?*]/g, '')}.${targetFormat.container}`;
    downloadLink.click();
    
    URL.revokeObjectURL(blobUrl);
  } catch (err) {
    console.error('跨域错误或链接无效,请使用前后端方案');
  }
}

关键注意事项

  • 必须通过用户主动触发的事件(如按钮点击)调用下载逻辑,否则会被浏览器拦截。
  • 文件名需过滤特殊字符(如<>:"/\|?*),避免保存时出错。
  • 可通过ytdl-core的chooseFormat方法自定义视频质量、格式(如仅选mp4格式)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 16:30:44