下载文件的详细讲解

  1. 音频文件下载的核心实现逻辑
    (1)后端接口适配:GET + Query 参数传递
typescript 复制代码
// downloadMusic API 定义
export const downloadMusic = (musicId: string, quality: number) => {
  return axios({
    url: '/api/music/downloadMusic',
    method: 'GET',
    params: { musicId, quality }, // Query 参数(URL拼接)
    responseType: 'blob', // 关键:指定二进制响应类型
    headers: { Authorization: localStorage.getItem('auth_token') || '' }, // Token 认证
  })
}
  • Query 参数:后端改为 Query 传参后,通过 params 字段传递,Axios 会自动拼接为
    ?musicId=xxx&quality=xxx,避免手动拼接 URL 导致编码错误;
  • responseType: 'blob':这是文件下载的核心配置 ------ 告诉 Axios 不要把响应解析为 JSON /
    字符串,而是保留原始二进制流(Blob 对象),否则音频文件会被破坏。

(2)前端文件下载触发:URL.createObjectURL + a 标签

typescript 复制代码
// 处理二进制流下载
const blob = response.data // Axios 返回的 Blob 对象
const url = window.URL.createObjectURL(blob) // 生成临时 URL
const link = document.createElement('a')
link.href = url
link.download = `${song.musicName}-${command.quality}.mp3` // 自定义文件名
link.click() // 触发浏览器下载
// 清理临时资源
setTimeout(() => {
  document.body.removeChild(link)
  window.URL.revokeObjectURL(url) // 释放内存,避免泄漏
}, 100)
  • URL.createObjectURL:为 Blob 对象生成浏览器可识别的临时 URL(如
    blob:http://localhost:8080/xxx),作为 a 标签的下载地址;
  • download 属性:指定下载文件的名称和后缀,浏览器会自动触发「保存文件」行为,而非打开文件
  • 资源清理:下载完成后必须调用 revokeObjectURL 释放临时 URL,否则会导致内存泄漏(尤其频繁下载时)。

(3)响应类型判断:兼容错误场景

typescript 复制代码
const contentType = response.headers['content-type'] || response.headers['Content-Type']
if (contentType.includes('application/json')) {
  // 后端返回 JSON 错误(如参数错误),解析错误信息
  const text = await response.data.text()
  const errorData = JSON.parse(text)
  ElMessage.error(errorData.errorMsg || '下载失败')
} else {
  // 二进制流,执行下载逻辑
}
  • 后端可能在接口异常时返回 JSON 错误(而非二进制流),需通过 Content-Type 区分响应类型,避免把错误 JSON
    当成音频文件下载。

(4)下载状态控制:防止重复请求

typescript 复制代码
const downloading = ref(false)
const handleDownload = async (command) => {
  if (downloading.value) return // 已有下载请求时,阻止重复触发
  downloading.value = true
  try {
    // 下载逻辑
  } catch (error) {
    // 错误处理
  } finally {
    downloading.value = false // 无论成功/失败,重置状态
  }
}
  • 通过 downloading 状态锁,避免用户短时间内多次点击下载按钮,导致重复请求和资源浪费。

(5)音质映射与文件名处理

typescript 复制代码
// 音质名称 → 后端识别的数字值
const qualityMap = { 标清: 1, 高清: 2, 无损: 3, 空间音频: 4 }
// 文件名:兼容不同音频格式(MP3/FLAC)
const fileName = `${song.musicName || '未知歌`在这里插入代码片`曲'}-${command.quality}.${contentType.includes('flac') ? 'flac' : 'mp3'}`
  • 前端展示「标清 / 高清」等友好名称,后端接收数字编码,通过映射表统一格式;
  • 根据响应的 Content-Type 动态设置文件后缀(如无损音质返回 FLAC 格式),确保文件能被播放器识别。
相关推荐
橘子编程1 天前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
数据知道2 天前
claw-code 源码分析:从 TypeScript 心智到 Python/Rust——跨栈移植时类型、边界与错误模型怎么对齐?
python·ai·rust·typescript·claude code·claw code
luckyCover2 天前
TypeScript学习系列(二):高级类型篇
前端·typescript
qq_381338502 天前
TypeScript 类型安全与类型体操实战:从入门到精通
javascript·安全·typescript
We་ct2 天前
LeetCode 69. x 的平方根:两种解法详解
前端·javascript·算法·leetcode·typescript·平方
zhensherlock2 天前
Protocol Launcher 系列:Mail Assistant 轻松发送 HTML 邮件
前端·javascript·typescript·node.js·html·github·js
军军君013 天前
Three.js基础功能学习十八:智能黑板实现实例五
前端·javascript·vue.js·3d·typescript·前端框架·threejs
军军君013 天前
Three.js基础功能学习十四:智能黑板实现实例一
前端·javascript·css·typescript·前端框架·threejs·智能黑板
We་ct3 天前
LeetCode 172. 阶乘后的零:从暴力到最优,拆解解题核心
开发语言·前端·javascript·算法·leetcode·typescript
军军君013 天前
数字孪生监控大屏实战模板:可视化数字统计展示
前端·javascript·vue.js·typescript·echarts·数字孪生·前端大屏