下载文件的详细讲解

  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 格式),确保文件能被播放器识别。
相关推荐
北寻北爱2 小时前
TypeScript知识点汇总及相关面试题
typescript
晓13133 小时前
第三章 TypeScript 高级类型
前端·javascript·typescript
晓13135 小时前
第四章 TypeScript 类型声明文件与 React 运用
前端·react.js·typescript
~欲买桂花同载酒~5 小时前
项目安装- React + TypeScript
前端·react.js·typescript
ssshooter5 小时前
infer,TS 类型系统的手术刀
前端·面试·typescript
We་ct5 小时前
LeetCode 162. 寻找峰值:二分高效求解
前端·算法·leetcode·typescript·二分·暴力
MIka1 天前
CopilotKit 入门:用 Runtime 和 React Core 搭建真正可用的 AI Copilot
人工智能·typescript·agent
学以智用1 天前
# TypeScript 高级特性(核心+实用)
前端·javascript·typescript
学以智用1 天前
TypeScript 核心基础:类型/变量 + 函数 + 接口
前端·javascript·typescript