前端vue3调取阿里的oss存储

1. 整体流程概述

前端使用阿里云OSS上传文件的完整流程如下:

  1. 调用后端接口获取临时密钥
  2. 使用临时密钥初始化OSS客户端
  3. 调用OSS客户端上传文件
  4. 获取上传成功后的文件URL

2. 后端接口调用(获取临时密钥)

2.1 接口信息

  • 接口地址 : /pc/file/sts
  • 请求方式 :GET
  • 返回格式 :JSON

2.2 返回参数说明

javascript 复制代码
{
  "code": 200, // 状态码,0或200表示成功
  "msg": "操作成功",
  "data": {
    "accessKeyId": "STS.NZQpZ...", // 临时AccessKeyId
    "accessKeySecret": "LJ8Z8...", // 临时AccessKeySecret
    "securityToken": "CAIS+...", // 临时安全令牌
    "endpoint": "oss-cn-hangzhou.aliyuncs.com", // OSS地域节点
    "bucketName": "rh-app-private", // OSS存储空间名称
    "bucketDomain": "https://rh-app-private.oss-cn-hangzhou.aliyuncs.com" // OSS存储空间域名
  }
}

2.3 前端调用代码

javascript 复制代码
import api from '@/utils/api'

export const getSTSToken = async () => {
  try {
    const response = await api.get('/pc/file/sts')
    if (response.code === 200) {
      return response.data
    } else {
      throw new Error('获取STS密钥失败: ' + (response.msg || '未知错误'))
    }
  } catch (error) {
    console.error('获取STS密钥失败:', error)
    throw error
  }
}

3. OSS客户端初始化

3.1 安装阿里云OSS SDK

javascript 复制代码
npm install ali-oss

3.2 初始化OSS客户端

javascript 复制代码
import OSS from 'ali-oss'
import { getSTSToken } from './sts'

let client = null

export const initOSSClient = async () => {
  try {
    const token = await getSTSToken()
    
    // 解析region:从endpoint中提取region部分
    let region = token.endpoint
    if (token.endpoint && token.endpoint.includes('.')) {
      const parts = token.endpoint.split('.')
      if (parts.length >= 3 && parts[0].startsWith('oss-')) {
        region = parts[0]
      } else {
        region = parts[0]
        console.warn('非标准OSS endpoint格式:', region)
      }
    }
    
    // 存储bucketDomain以便上传时使用
    window.ossBucketDomain = token.bucketDomain
    
    // 创建OSS客户端实例
    client = new OSS({
      region: region, // 区域
      endpoint: token.endpoint, // 地域节点
      accessKeyId: token.accessKeyId, // 临时AccessKeyId
      accessKeySecret: token.accessKeySecret, // 临时AccessKeySecret
      stsToken: token.securityToken, // 临时安全令牌
      bucket: token.bucketName, // 存储空间名称
      
      // 配置自动刷新临时密钥
      refreshSTSToken: async () => {
        const newToken = await getSTSToken()
        return {
          accessKeyId: newToken.accessKeyId,
          accessKeySecret: newToken.accessKeySecret,
          stsToken: newToken.securityToken
        }
      },
      
      // 刷新间隔:5分钟
      refreshSTSTokenInterval: 300000
    })
    
    console.log('OSS客户端初始化成功')
    return client
  } catch (error) {
    console.error('OSS客户端初始化失败:', error)
    throw error
  }
}

4. 文件上传实现

4.1 文件上传函数

javascript 复制代码
export const uploadFileToOSS = async (file, type, phone, name) => {
  try {
    // 确保OSS客户端已初始化
    if (!client) {
      await initOSSClient()
    }
    
    // 获取文件后缀
    const fileExt = file.name.substring(file.name.lastIndexOf('.'))
    const timestamp = Date.now()
    
    // 根据文件类型生成不同的路径和文件名
    let filePath
    if (type === 'front' || type === 'back') {
      // 身份证照片 - /Doctor_ID/手机号_医生姓名_时间戳.图片后缀
      const folder = '/Doctor_ID/'
      filePath = `${folder}${phone}_${name}_${timestamp}${fileExt}`
    } else if (type === 'medicalFront' || type === 'medicalBack') {
      // 医师执业资格证照片 - /Doctor_PPC/手机号_医生姓名_时间戳.图片后缀
      const folder = '/Doctor_PPC/'
      filePath = `${folder}${phone}_${name}_${timestamp}${fileExt}`
    } else {
      // 其他类型文件
      filePath = `${type}-${timestamp}-${Math.random().toString(36).substring(2, 10)}${fileExt}`
    }
    
    // 上传文件
    const result = await client.put(filePath, file)
    
    // 返回文件URL - 优先使用bucketDomain构建URL
    let fileUrl = result.url
    if (window.ossBucketDomain && filePath) {
      // 移除filePath开头可能的斜杠
      const cleanFilePath = filePath.startsWith('/') ? filePath.substring(1) : filePath
      fileUrl = `${window.ossBucketDomain}/${cleanFilePath}`
    }
    
    return fileUrl
  } catch (error) {
    console.error('OSS上传失败:', error)
    throw new Error('文件上传失败')
  }
}

4.2 调用上传函数

javascript 复制代码
// 在Vue组件中调用
const handleFileChange = async (event, type) => {
  const file = event.target.files[0]
  if (!file) return
  
  try {
    // 显示上传中提示
    showToast({ message: '上传中...', duration: 0 })
    
    // 上传到OSS,传递必要参数
    const imageUrl = await uploadFileToOSS(file, type, form.phone, form.name)
    
    // 存储图片URL
    if (type === 'front') {
      form.frontIdCard = imageUrl
    } else if (type === 'back') {
      form.backIdCard = imageUrl
    } else if (type === 'medicalFront') {
      form.medicalFront = imageUrl
    } else if (type === 'medicalBack') {
      form.medicalBack = imageUrl
    }
    
    showToast('图片上传成功')
  } catch (error) {
    console.error('图片上传失败:', error)
    showToast('图片上传失败,请稍后重试')
    // 清空文件输入
    event.target.value = ''
  }
}

5. 文件命名规范

5.1 身份证照片

  • 路径格式 : /Doctor_ID/手机号_医生姓名_时间戳.图片后缀
  • 示例 : /Doctor_ID/13800138000_张三_1734478800000.jpg

5.2 医师执业资格证照片

  • 路径格式 : /Doctor_PPC/手机号_医生姓名_时间戳.图片后缀
  • 示例 : /Doctor_PPC/13800138000_张三_1734478800000.jpg

6. 错误处理

6.1 接口调用错误

javascript 复制代码
try {
  const response = await api.get('/pc/file/sts')
  // 处理响应
} catch (error) {
  console.error('获取STS密钥失败:', error)
  showToast('OSS初始化失败,图片上传功能可能不可用')
}

6.2 文件上传错误

javascript 复制代码
try {
  const result = await client.put(filePath, file)
  // 处理上传结果
} catch (error) {
  console.error('OSS上传失败:', error)
  showToast('文件上传失败,请稍后重试')
}

7. 关键代码示例

7.1 完整的OSS工具类(src/utils/oss.js)

javascript 复制代码
import OSS from 'ali-oss'
import api from '@/utils/api'

// 全局OSS客户端实例
let client = null

// 获取STS临时密钥
export const getSTSToken = async () => {
  try {
    const response = await api.get('/pc/file/sts')
    if (response.code === 0 || response.code === 200) {
      return response.data
    } else {
      throw new Error('获取STS密钥失败: ' + (response.msg || '未知错误'))
    }
  } catch (error) {
    console.error('获取STS密钥失败:', error)
    throw error
  }
}

// 初始化OSS客户端
export const initOSSClient = async () => {
  try {
    const token = await getSTSToken()
    
    // 解析region
    let region = token.endpoint
    if (token.endpoint && token.endpoint.includes('.')) {
      const parts = token.endpoint.split('.')
      if (parts.length >= 3 && parts[0].startsWith('oss-')) {
        region = parts[0]
      } else {
        region = parts[0]
        console.warn('非标准OSS endpoint格式:', region)
      }
    }
    
    // 存储bucketDomain
    window.ossBucketDomain = token.bucketDomain
    
    // 创建OSS客户端实例
    client = new OSS({
      region: region,
      endpoint: token.endpoint,
      accessKeyId: token.accessKeyId,
      accessKeySecret: token.accessKeySecret,
      stsToken: token.securityToken,
      bucket: token.bucketName,
      refreshSTSToken: async () => {
        const newToken = await getSTSToken()
        return {
          accessKeyId: newToken.accessKeyId,
          accessKeySecret: newToken.accessKeySecret,
          stsToken: newToken.securityToken
        }
      },
      refreshSTSTokenInterval: 300000
    })
    
    return client
  } catch (error) {
    console.error('OSS客户端初始化失败:', error)
    throw error
  }
}

// 上传文件到OSS
export const uploadFileToOSS = async (file, type, phone, name) => {
  try {
    if (!client) {
      await initOSSClient()
    }
    
    const fileExt = file.name.substring(file.name.lastIndexOf('.'))
    const timestamp = Date.now()
    
    let filePath
    if (type === 'front' || type === 'back') {
      const folder = '/Doctor_ID/'
      filePath = `${folder}${phone}_${name}_${timestamp}${fileExt}`
    } else if (type === 'medicalFront' || type === 'medicalBack') {
      const folder = '/Doctor_PPC/'
      filePath = `${folder}${phone}_${name}_${timestamp}${fileExt}`
    } else {
      filePath = `${type}-${timestamp}-${Math.random().toString(36).substring(2, 10)}${fileExt}`
    }
    
    const result = await client.put(filePath, file)
    
    let fileUrl = result.url
    if (window.ossBucketDomain && filePath) {
      const cleanFilePath = filePath.startsWith('/') ? filePath.substring(1) : filePath
      fileUrl = `${window.ossBucketDomain}/${cleanFilePath}`
    }
    
    return fileUrl
  } catch (error) {
    console.error('OSS上传失败:', error)
    throw new Error('文件上传失败')
  }
}

8. 注意事项

  1. 临时密钥有效期 :临时密钥通常有一定的有效期(默认1小时),代码中配置了自动刷新机制
  2. 文件大小限制 :建议在前端添加文件大小限制(如10MB),避免上传过大文件
  3. 错误处理 :完善的错误处理可以提高用户体验
  4. CORS配置 :确保OSS存储空间已正确配置CORS规则,允许前端域名访问
  5. 网络稳定性 :考虑添加重试机制,提高弱网络环境下的上传成功率
    通过以上流程,前端可以安全、高效地将文件上传到阿里云OSS,并获取可用的文件URL用于后续业务处理。
相关推荐
luquinn5 小时前
用canvas切图展示及标记在原图片中的位置
开发语言·前端·javascript
AAA阿giao5 小时前
React Hooks 详解:从 useState 到 useEffect,彻底掌握函数组件的“灵魂”
前端·javascript·react.js
RedHeartWWW5 小时前
Next.js Middleware 极简教程
前端
饼饼饼5 小时前
从 0 到 1:前端 CI/CD 实战 ( 第一篇: 云服务器环境搭建)
运维·前端·自动化运维
用户47949283569156 小时前
给前端明星开源项目Biome提 PR,被 Snapshot 测试坑了一把
前端·后端·测试
૮・ﻌ・6 小时前
小兔鲜电商项目(一):项目准备、Layout模块、Home模块
前端·javascript·vue
dy17176 小时前
vue左右栏布局可拖拽
前端·css·html
zhougl9966 小时前
AJAX本质与核心概念
前端·javascript·ajax
GISer_Jing6 小时前
Taro跨端开发实战:核心原理与关键差异解析
前端·javascript·taro