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

开发HTML视频下载器遇阻:fetch/axios失效,是否方案有误?

前端视频下载方案问题排查与修正

我正在尝试创建一个HTML文件来提取并下载视频,之前用fetch和axios实现但没成功,不确定当前方案是否有误,附上代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Video Downloader</title>
  </head>
  <body>
    <h1>Video Downloader</h1>
    <p>Enter the URL of the video you want to download:</p>
    <input type="text" id="video-url" placeholder="Video URL">
    <button onclick="downloadVideo()">Download</button>
    <div id="error-message"></div>

    <script src="https://cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg"></script>
    <script>
      async function downloadVideo() {
        const videoUrl = document.getElementById('video-url').value;

        try {
          const response = await fetch(videoUrl);
          const contentType = response.headers.get('Content-Type');
          const extension = contentType.split('/')[1];
          const blob = await response.blob();

          let videoBlob;
          if (extension === 'mp4') {
            videoBlob = blob;
          } else {
            const ffmpeg = createFFmpeg({ log: true });
            await ffmpeg.load();
            ffmpeg.FS('writeFile', 'video', await fetchFile(blob));
            await ffmpeg.run('-i', 'video', '-c', 'copy', '-movflags', 'frag_keyframe+empty_moov', 'video.mp4');
            videoBlob = await fetchFile(ffmpeg.FS('readFile', 'video.mp4'));
          }

          const url = window.URL.createObjectURL(videoBlob);
          const a = document.createElement('a');
          a.href = url;
          a.download = 'video.mp4';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
        } catch (error) {
          const errorMessage = document.getElementById('error-message');
          errorMessage.textContent = `Error downloading video: ${error}`;
        }
      }

      async function fetchFile(file) {
        const response = await fetch(file);
        return new Uint8Array(await response.arrayBuffer());
      }
    </script>
  </body>
</html>

你的方案方向没问题,但存在3个关键问题导致无法正常工作:

  • 跨域限制:直接用fetch请求外部视频URL会触发浏览器CORS策略,除非目标服务器配置了允许跨域的响应头,否则请求会直接失败。
  • fetchFile函数误用:当参数是Blob对象时,fetch函数无法直接处理,这个自定义函数的逻辑错误,会导致FFmpeg无法正确读取视频文件。
  • FFmpeg处理逻辑漏洞:非MP4格式转码时,没有处理FFmpeg运行可能出现的错误,且转码后的文件转换为Blob的方式有误。

修正后的代码示例

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Video Downloader</title>
  </head>
  <body>
    <h1>Video Downloader</h1>
    <p>输入要下载的视频URL:</p>
    <input type="text" id="video-url" placeholder="视频URL">
    <button onclick="downloadVideo()">下载</button>
    <div id="error-message" style="color:red;margin-top:10px;"></div>

    <script src="https://cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg@0.12.6/dist/ffmpeg.min.js"></script>
    <script>
      const { createFFmpeg, fetchFile } = FFmpeg;

      async function downloadVideo() {
        const videoUrl = document.getElementById('video-url').value;
        const errorMsgEl = document.getElementById('error-message');
        errorMsgEl.textContent = '';

        try {
          // 跨域问题需要目标服务器允许CORS,否则请求会失败
          const response = await fetch(videoUrl, { mode: 'cors' });

          if (!response.ok) {
            throw new Error(`HTTP请求失败!状态码:${response.status}`);
          }

          const contentType = response.headers.get('Content-Type');
          let videoBlob;

          if (contentType?.includes('mp4')) {
            videoBlob = await response.blob();
          } else {
            const ffmpeg = createFFmpeg({ log: true });
            await ffmpeg.load();
            
            // 直接读取响应的ArrayBuffer,无需误用fetch函数
            const videoBuffer = await response.arrayBuffer();
            ffmpeg.FS('writeFile', 'input-video', new Uint8Array(videoBuffer));
            
            // 使用H.264/AAC编码保证MP4兼容性,而非直接拷贝流(避免编码不兼容)
            await ffmpeg.run('-i', 'input-video', '-c:v', 'libx264', '-c:a', 'aac', 'output.mp4');
            
            const outputData = ffmpeg.FS('readFile', 'output.mp4');
            videoBlob = new Blob([outputData], { type: 'video/mp4' });
            
            // 清理FFmpeg文件系统,避免内存占用
            ffmpeg.FS('unlink', 'input-video');
            ffmpeg.FS('unlink', 'output.mp4');
          }

          const url = window.URL.createObjectURL(videoBlob);
          const a = document.createElement('a');
          a.href = url;
          a.download = `下载视频-${Date.now()}.mp4`;
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          // 释放Blob URL资源
          window.URL.revokeObjectURL(url);
        } catch (error) {
          errorMsgEl.textContent = `下载失败: ${error.message}`;
          console.error(error);
        }
      }
    </script>
  </body>
</html>

核心限制说明

  1. 跨域问题:这是前端方案的最大瓶颈,大部分视频网站不会配置允许跨域的响应头,这种情况下必须通过后端代理转发请求才能解决。
  2. FFmpeg性能:浏览器端运行FFmpeg对设备性能要求较高,大体积视频转码会耗时久,甚至导致页面卡顿。
  3. 格式支持:FFmpeg.wasm并非支持所有视频编码,部分罕见格式可能无法完成转码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 18:15:59