vue3使用七牛云上传文件
以下是一个完整的 Vue 3 集成七牛云文件上传 的解决方案,包含环境搭建、代码实现和注意事项:
一、环境准备
-
安装七牛云 SDK
bash
npm install qiniu-js@3.4.2 # 推荐使用稳定版本
-
获取七牛云配置
- 在七牛云控制台创建 存储空间,获取以下信息:
AccessKey
和SecretKey
(用于服务端生成上传凭证)Bucket 名称
和存储空间域名
(如your-bucket.qiniucdn.com
)
- 在七牛云控制台创建 存储空间,获取以下信息:
二、完整代码实现
组件文件:QiniuUpload.vue
<template><div class="qiniu-upload-container"><!-- 文件选择按钮 --><inputtype="file"ref="fileInput"@change="handleFileChange"accept="image/*,video/*,application/pdf" <!-- 支持多类型 -->style="display: none"/><button @click="triggerFileSelect">选择文件</button><!-- 上传按钮 --><button@click="handleUpload":disabled="!file || isUploading || !qiniuReady"class="upload-button">{{ isUploading ? '上传中...' : '开始上传' }}</button><!-- 上传进度 --><div v-if="isUploading" class="progress-bar">进度:{{ progress }}%</div><!-- 结果展示 --><div v-if="fileUrl" class="preview-container"><span>已上传:</span><a :href="fileUrl" target="_blank" rel="noopener">{{ fileName }}</a><!-- 图片预览 --><imgv-if="isImageFile":src="fileUrl"alt="预览"class="preview-image"/></div><!-- 错误提示 --><div v-if="error" class="error-message">{{ error }}</div></div>
</template><script setup>
import { ref, onMounted, watch } from 'vue';
import qiniu from 'qiniu-js'; // 导入七牛云 SDK// 响应式状态
const file = ref(null); // 选中的文件
const isUploading = ref(false);
const progress = ref(0);
const fileUrl = ref('');
const fileName = ref('');
const error = ref('');
const qiniuReady = ref(false); // SDK 就绪状态
const isImageFile = ref(false); // 是否为图片文件// 七牛云配置(需替换为你的实际信息)
const bucket = 'your-bucket-name'; // 存储空间名称
const domain = 'your-bucket.qiniucdn.com'; // 存储空间域名
const region = qiniu.region.z2; // 空间区域(根据实际区域修改,如 z0、z1、z2 等)// 初始化 SDK
onMounted(() => {// 验证 SDK 可用性if (qiniu && qiniu.upload) {qiniuReady.value = true;} else {error.value = '七牛云 SDK 加载失败,请检查依赖';}
});// 触发文件选择
const triggerFileSelect = () => {fileInput.value.click();
};// 文件选择处理
const fileInput = ref(null);
const handleFileChange = (e) => {const selectedFile = e.target.files?.[0];if (!selectedFile) return;file.value = selectedFile;fileName.value = selectedFile.name;isImageFile.value = selectedFile.type.startsWith('image/');error.value = ''; // 清除之前的错误
};// 上传文件
const handleUpload = async () => {if (!file.value || !qiniuReady.value || isUploading.value) return;try {isUploading.value = true;progress.value = 0;// 1. 获取上传凭证(需先实现服务端接口)const token = await fetchUploadToken();// 2. 创建上传配置const config = {useCdnDomain: true, // 使用 CDN 加速域名region, // 空间区域};// 3. 生成唯一文件名(避免重复)const key = generateUniqueFileName(file.value);// 4. 执行上传const observable = qiniu.upload(file.value, // 上传的文件对象key, // 自定义文件名(可选,不填则使用原始文件名)token, // 上传凭证{fname: file.value.name, // 原始文件名(可选)mimeType: file.value.type, // 文件 MIME 类型(可选)},config);// 5. 订阅上传进度和结果const subscription = observable.subscribe({next: (res) => {progress.value = Math.round(res.total.percent); // 更新进度},error: (err) => {isUploading.value = false;error.value = `上传失败:${err.message}`;console.error('上传错误:', err);},complete: (res) => {isUploading.value = false;fileUrl.value = `https://${domain}/${res.key}`; // 构建文件访问地址console.log('上传成功:', res);},});// 6. 清理订阅(组件卸载时)watch(() => isUploading.value, (newVal) => {if (!newVal && subscription) {subscription.unsubscribe();}});} catch (err) {isUploading.value = false;error.value = `操作失败:${err.message}`;}
};// 生成唯一文件名(时间戳+随机字符串)
const generateUniqueFileName = (file) => {const ext = file.name.split('.').pop();const timestamp = Date.now();const randomStr = Math.random().toString(36).substring(2, 10);return `${timestamp}_${randomStr}.${ext}`;
};// 获取上传凭证(需对接你的服务端接口)
const fetchUploadToken = async () => {try {const response = await fetch('/api/qiniu/get-token', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ bucket }), // 传递 Bucket 名称给服务端});if (!response.ok) throw new Error('获取凭证失败');const data = await response.json();if (!data.token) throw new Error('凭证无效');return data.token;} catch (err) {throw new Error(`获取凭证失败:${err.message}`);}
};
</script><style scoped>
.qiniu-upload-container {max-width: 600px;margin: 20px auto;padding: 20px;border: 1px solid #e5e7eb;border-radius: 8px;
}.upload-button {background-color: #3b82f6;color: white;padding: 8px 16px;border: none;border-radius: 4px;cursor: pointer;margin-left: 10px;
}.progress-bar {height: 4px;background-color: #e5e7eb;margin: 10px 0;border-radius: 2px;position: relative;
}.progress-bar::before {content: '';height: 100%;width: ${(props) => props.progress}%;background-color: #3b82f6;border-radius: 2px;transition: width 0.3s ease;
}.preview-container {margin-top: 20px;padding: 15px;border: 1px dashed #e5e7eb;border-radius: 4px;
}.preview-image {max-width: 300px;max-height: 200px;margin-top: 10px;display: block;
}.error-message {color: #dc2626;margin-top: 10px;
}
</style>
三、关键配置说明
-
空间区域(Region)配置
七牛云不同区域对应不同的region
值,需根据你的存储空间所在地选择:- 华东区域(z0):
qiniu.region.z0
- 华北区域(z1):
qiniu.region.z1
- 华南区域(z2):
qiniu.region.z2
- 北美区域(na0):
qiniu.region.na0
- 东南亚区域(as0):
qiniu.region.as0
- 华东区域(z0):
-
文件类型限制
通过accept
属性限制允许上传的文件类型:html
预览
accept="image/*,video/*,application/pdf" <!-- 允许图片、视频、PDF -->
-
安全注意事项
- 永远不要在前端暴露 AccessKey/SecretKey,必须通过服务端生成上传凭证。
- 对上传的文件进行大小限制(前端和服务端双重校验):
javascript
// 前端校验(示例:限制 50MB) const maxFileSize = 50 * 1024 * 1024; // 50MB if (file.value.size > maxFileSize) {error.value = '文件大小不能超过 50MB';file.value = null;return; }
四、常见问题解决
-
上传凭证失效
- 确保服务端接口返回的 Token 未过期(默认有效期 3600 秒)。
- 检查 Bucket 名称是否正确。
-
跨域问题
- 若文件访问地址出现跨域,需在七牛云控制台配置 CORS 规则。
-
SDK 加载失败
- 确认
qiniu-js
已正确安装,且导入路径无误:javascript
import qiniu from 'qiniu-js'; // 确保包名正确
- 确认
-
进度条不更新
- 确保订阅了
next
事件,并正确更新progress
状态。
- 确保订阅了
五、效果演示
- 选择文件后点击上传,显示实时进度。
- 上传成功后显示文件链接和预览(图片文件)。
- 错误场景(如文件过大、凭证失效)显示友好提示。
通过以上方案,可实现安全、高效的 Vue 3 七牛云文件上传功能。如有具体问题,请提供错误日志或配置细节,以便进一步排查!