vue 上传文件到 OSS

在 Vue 项目中实现不经过后端服务器直接上传文件到阿里云 OSS,可通过以下几种方案实现。以下是综合各来源的最佳实践和注意事项:


方案一:使用 OSS SDK 直传(前端配置密钥,不推荐)

  1. 安装依赖
shell 复制代码
npm install ali-oss --save
  1. 封装上传方法
    utils/oss.js 中创建客户端实例并封装上传逻辑:
js 复制代码
import OSS from 'ali-oss';
const client = new OSS({
  region: 'oss-cn-hangzhou', // 替换为你的区域
  accessKeyId: 'your-access-key-id', // 阿里云 AccessKeyId
  accessKeySecret: 'your-access-key-secret', // 阿里云 AccessKeySecret
  bucket: 'your-bucket-name' // OSS 存储桶名称
});
export async function uploadFile(file) {
  try {
    const fileName = `uploads/${file.name}`; // 自定义文件路径
    const result = await client.put(fileName, file);
    return result.url; // 返回文件访问地址
  } catch (error) {
    console.error('上传失败:', error);
    throw error;
  }
}
  1. Vue 组件调用
html 复制代码
<template>
  <input type="file" @change="handleUpload" />
</template>
<script>
import { uploadFile } from '@/utils/oss.js';
export default {
  methods: {
    async handleUpload(event) {
      const file = event.target.files[0];
      const url = await uploadFile(file);
      console.log('文件地址:', url);
    }
  }
};
</script>

注意:此方案需在前端暴露密钥,存在安全风险,仅适用于测试环境。


方案二:STS 临时凭证(推荐生产环境)

  1. 后端提供 STS 接口
    后端通过阿里云 STS 服务生成临时访问凭证(AccessKeyIdAccessKeySecretSecurityToken),并返回给前端。
  2. 前端动态获取凭证并上传
js 复制代码
import OSS from 'ali-oss';
import axios from 'axios';
async function uploadWithSTS(file) {
  // 1. 请求后端获取临时凭证
  const { data } = await axios.get('/api/sts-token');
  
  // 2. 使用临时凭证初始化 OSS 客户端
  const client = new OSS({
    region: data.region,
    accessKeyId: data.accessKeyId,
    accessKeySecret: data.accessKeySecret,
    stsToken: data.securityToken,
    bucket: data.bucketName
  });
  // 3. 上传文件
  const result = await client.put(`uploads/${file.name}`, file);
  return result.url;
}

优势:避免密钥暴露,凭证有效期可控。


方案三:服务端签名后直传

  1. 后端生成签名策略
    后端根据 OSS 要求生成 policysignature,返回给前端。
  2. 前端通过表单提交
js 复制代码
async function uploadWithSignature(file) {
  const { data } = await axios.get('/api/oss-signature'); // 获取签名信息
  const formData = new FormData();
  formData.append('key', `uploads/${file.name}`);
  formData.append('policy', data.policy);
  formData.append('OSSAccessKeyId', data.accessId);
  formData.append('signature', data.signature);
  formData.append('file', file);
  const res = await axios.post(data.host, formData, {
    headers: { 'Content-Type': 'multipart/form-data' }
  });
  return `${data.host}/${formData.get('key')}`; // 返回文件地址
}

适用场景:无需 SDK,兼容性强。


关键注意事项

  1. 跨域配置
    在阿里云 OSS 控制台配置跨域规则,允许 POSTPUT 方法,并设置允许来源(如 * 或具体域名)。
  2. 文件命名
    避免文件名冲突,建议使用唯一标识(如 UUID + 时间戳):
js 复制代码
const fileName = `${Date.now()}-${Math.random().toString(36).substring(2)}.${file.name.split('.').pop()}`;
  1. 大文件分片上传
    使用 multipartUpload 方法处理大文件,支持进度回调:
js 复制代码
const result = await client.multipartUpload(fileName, file, {
  progress: (p) => console.log(`上传进度: ${(p * 100).toFixed(2)}%`)
});
  1. 取消上传
    通过 client.cancel() 中断上传任务。

方案对比

方案 安全性 适用场景 依赖
SDK 直传 低(密钥暴露) 测试环境 ali-oss
STS 临时凭证 生产环境 ali-oss + 后端接口
服务端签名直传 兼容旧项目 无 SDK

完整示例(STS 方案)

html 复制代码
<template>
  <el-upload
    action="#"
    :http-request="customUpload"
    :show-file-list="false"
  >
    <el-button>选择文件</el-button>
  </el-upload>
</template>
<script>
import OSS from 'ali-oss';
import axios from 'axios';
export default {
  methods: {
    async customUpload({ file }) {
      try {
        // 异步获取临时凭证
        const { data } = await axios.get('/api/sts-token');
        
        // 初始化 OSS 客户端
        const client = new OSS({
          region: data.region,
          accessKeyId: data.accessKeyId,
          accessKeySecret: data.accessKeySecret,
          stsToken: data.securityToken,
          bucket: data.bucketName
        });
        // 上传并获取地址
        const result = await client.put(`uploads/${file.name}`, file);
        this.$message.success(`上传成功: ${result.url}`);
      } catch (error) {
        this.$message.error('上传失败');
      }
    }
  }
};
</script>

根据安全需求选择方案:生产环境优先使用 STS 临时凭证服务端签名,测试环境可简化为 SDK 直传。更多细节可参考阿里云官方文档或各来源的完整代码。

相关推荐
拖拉斯旋风2 小时前
🧠 `useRef`:React 中“默默记住状态却不打扰 UI”的利器
前端·javascript·react.js
明月_清风2 小时前
GSAP + ScrollTrigger 实现滚动驱动动画详解
前端
代码猎人2 小时前
如何实现一个三角形
前端
龙国浪子2 小时前
从点到线,从线到画:Canvas 画笔工具的实现艺术
前端·electron
代码猎人2 小时前
什么是margin重叠,如何解决
前端
TeamDev2 小时前
使用 Vue.js 构建 Java 桌面应用
java·前端·vue.js
DongHao2 小时前
跨域问题及解决方案
前端·javascript·面试
持续升级打怪中2 小时前
Vue项目中Axios全面封装实战指南
前端·javascript·vue.js
heyCHEEMS2 小时前
为什么放弃 v-if 选择 v-show?为什么组件越用越卡?
前端