下载文件的详细讲解

  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 格式),确保文件能被播放器识别。
相关推荐
OpenTiny社区7 小时前
操作ArkTS页面跳转及路由相关心得
前端·typescript·web·opentiny
柠檬の夏季7 小时前
TypeScript入门
typescript
万物皆对象6667 小时前
切换路由时页面空白问题(vue3)
前端·vue.js·typescript
突然好热7 小时前
TS 调试技巧
前端·javascript·typescript
晓杰'15 小时前
从0到1实现Balatro游戏后端(5):得分计算与单局结算流程实现
后端·typescript·node.js·游戏开发·项目实战·nestjs·webscoket
追光者♂16 小时前
【测评系列3】CSDN AI数字营销实测体验官:测试 开源项目——Superpowers 游戏引擎从零开发实战指南
人工智能·深度学习·机器学习·typescript·开源·游戏引擎·superpowers
ct97816 小时前
TypeScript 中的泛型
前端·javascript·typescript
烛衔溟1 天前
TypeScript 类的类型 —— 作为类型使用
javascript·ubuntu·typescript
阿隅1 天前
TS 深度解析:同为 ? 可选语法,为什么赋值一错一对?类类型与this绑定底层拆解
typescript
Patrick_Wilson1 天前
前端解析接口数据,到底该不该信任后端?聊聊「防御性编程」与「类型契约」的边界
架构·typescript·代码规范