前端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用于后续业务处理。
相关推荐
wearegogog12331 分钟前
基于 MATLAB 的卡尔曼滤波器实现,用于消除噪声并估算信号
前端·算法·matlab
Drawing stars38 分钟前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
品克缤43 分钟前
Element UI MessageBox 增加第三个按钮(DOM Hack 方案)
前端·javascript·vue.js
小二·1 小时前
Python Web 开发进阶实战:性能压测与调优 —— Locust + Prometheus + Grafana 构建高并发可观测系统
前端·python·prometheus
小沐°1 小时前
vue-设置不同环境的打包和运行
前端·javascript·vue.js
qq_419854052 小时前
CSS动效
前端·javascript·css
烛阴2 小时前
3D字体TextGeometry
前端·webgl·three.js
桜吹雪2 小时前
markstream-vue实战踩坑笔记
前端
C_心欲无痕2 小时前
nginx - 实现域名跳转的几种方式
运维·前端·nginx
花哥码天下2 小时前
恢复网站console.log的脚本
前端·javascript·vue.js