likes
comments
collection
share

浏览器驯服录<之>一键保存视频到本地

作者站长头像
站长
· 阅读数 79

请听题:给定一个视频链接和一个按钮,如何实现点击按钮把视频保存到本地?

零、太长不看版

1、手动实现

  • 第 1 步:以视频 URL 手动发起 GET 请求,把响应数据转为 blob 格式的临时 URL;
  • 第 2 步:给 <a> 标签设置 download 属性,且 href 属性值为第 1 步生成的临时 URL;
  • 第 3 步:在 <a> 标签上触发点击,以触发浏览器的下载操作。

下方压缩包中是调试代码,运行方法参见压缩包中的 README.md

demo.zip

2、现成轮子

感谢掘友@修苟小狗的提醒,GitHub 上有现成可用的轮子:download。从源码来看,实现思路和本文大致相同,不想手动折腾的掘友们可以直接拿来用。


一、要做什么

最近遇到一个 CMS 需求,形态如下图所示:

浏览器驯服录<之>一键保存视频到本地

左侧是视频,视频资源信息(URL、封面图、时长、大小等)来自服务端接口;右侧有一个「下载视频」按钮。用户希望点一下按钮就把视频保存到本地。

首先来看实现细节。


二、如何实现

  1. 点击按钮时,发起一个 GET 请求,请求路径为视频 URL,并把响应数据转为 blob 格式。

    不同的网络请求 API 会有不同的设置方式,此处以 axios 为例:

    axios({
      url: videoUrl,
      method: 'GET',
      responseType: 'blob',
      timeout, // 可以根据视频体积动态地设置超时参数。
    }).then(blob => {
      ...
    })
    
  2. 接收到响应后,给 blob 文件生成一个临时 URL(形如:blob:``http://127.0.0.1:5500/c708f2b5-327e-4581-a267-4d8eb7f343b8):

    const tempUrl = window.URL.createObjectURL(blob)
    
  3. 创建一个 a 标签,href 属性的值为上一步生成的临时 URL;download 属性的值为字符串,代表保存时的文件名,可为空。

    const aTag = document.createElement('a')
    aTag.href = tempUrl
    aTag.download = ''
    
  1. 插入 a 标签并触发点击事件:

    document.body.appendChild(aTag)
    aTag.click()
    document.body.removeChild(aTag)
    
  1. 此时,浏览器界面会唤起文件保存窗口,用户可将视频保存到本地。

三、原理解析

在网页中点击超链接时,如果目标资源在浏览器中可预览,那么浏览器默认会直接打开资源进行预览,如 .html.png.mp4.mp3 等类型。

如果浏览器无法预览,则会弹出保存窗口,引导用户保存到本地,交由操作系统来处理,如 .zip 等类型。

<a> 标签支持一个 download 属性。当我们设置了 download(即使值为空字符串),标签被点击时,浏览器会将操作视为下载行为。

那么只要 <a> 标签有 download 属性就高枕无忧了吗?非也。

想要让 download 生效,使用场景需要符合以下条件之一

  • 资源地址与当前页面同源
  • href 值是 data:blob: 格式

我司的 CDN 静态资源与页面地址不同源,所以需要单独发起一次 GET 请求,把视频转为 blob 格式,并赋值给一个动态插入的 <a> 标签,再触发点击,促使浏览器执行文件保存操作。


四、结语

把文件保存到本地,是一个直觉上很容易实现的功能。但浏览器总是有那么一些小小的傲娇,我们需要借助一些小手段才能把它驯服。

感谢阅读。

如需勘误、讨论、建议,热烈欢迎留言。

转载自:https://juejin.cn/post/7169911036856762381
评论
请登录