如何自定义文件上传
背景说明
微搭平台提供了官方的文件上传组件,可以满足大多数基础的文件上传需求。但在实际业务场景中,我们常常需要对上传过程进行更精细的控制,例如:
- 文件类型限制:只允许上传特定格式的文件(如仅允许上传Word文档、Excel表格或图片等)
- 文件大小限制:限制上传文件的最大体积,避免过大文件占用存储空间
- 自定义存储路径:根据业务需求将文件存储到特定的路径下
- 文件内容校验:检查文件内容是否符合要求,如图片尺寸、文档页数等
- 上传前后处理:在上传前对文件进行预处理,或在上传后进行后续操作
- 自定义上传反馈:提供更友好的上传成功或失败提示
官方的上传组件可能无法完全满足这些个性化需求,此时我们可以通过自定义云函数来实现更灵活的文件上传功能。本文将介绍如何使用云函数实现自定义文件上传,并重点说明如何进行文件类型校验。
在使用微搭官方文件上传组件时,有时候我们需要自定义上传动作,例如添加文件类型校验、大小限制或自定义上传路径等。此时可以用自定义云函数实现文件上传,并增加所需的校验逻辑。
1. 自定义云函数与文件类型校验
在微搭环境下,新建一个云函数,并实现文件类型校验功能:
1.1 新增package.json文件
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@cloudbase/node-sdk": "latest",
"@cloudbase/manager-node": "^4.2.8",
"axios": "^1.6.3",
"form-data": "^4.0.0"
}
}
1.2 新增index.js文件(含文件类型校验)
下面的云函数代码包含了完整的文件类型校验实现:
'use strict';
const CloudBase = require("@cloudbase/manager-node");
const FormData = require("form-data");
const axios = require("axios");
const fs = require("fs");
const path = require("path");
exports.main = async (event, context) => {
const file = event.file // base64编码后的文件
const fileName = event.fileName // 文件名
const cloudPath = "./" + fileName; // 云端路径
const baseStr = file.split("base64,")[1]
const binaryData = Buffer.from(baseStr, 'base64');
// 初始化
const app = CloudBase.init({});
// 获取功能模块
const { storage } = app;
// ===== 文件类型校验开始 =====
// 1. 扩展名校验
const ext = path.extname(fileName).toLowerCase();
const allowedExtensions = [".docx", ".pdf", ".jpg", ".png", ".xlsx"];
if (!allowedExtensions.includes(ext)) {
return {
success: false,
result: "文件类型不支持,仅支持 docx、pdf、jpg、png、xlsx 格式"
}
}
// 2. MIME类型校验(可选,更严格的校验)
// 从base64字符串中提取MIME类型
if (file.includes("base64,")) {
const mimeType = file.split(";")[0].split(":")[1];
const allowedMimeTypes = [
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // docx
"application/pdf", // pdf
"image/jpeg", // jpg
"image/png", // png
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" // xlsx
];
if (!allowedMimeTypes.includes(mimeType)) {
return {
success: false,
result: "文件MIME类型不支持"
}
}
}
// 3. 文件大小校验
const fileSizeInBytes = binaryData.length;
const maxSizeInBytes = 10 * 1024 * 1024; // 10MB
if (fileSizeInBytes > maxSizeInBytes) {
return {
success: false,
result: "文件大小超过限制,最大支持10MB"
}
}
// 4. 特定文件类型的内容校验(示例)
// 这里可以添加针对特定文件类型的内容校验
// 例如:检查图片尺寸、文档页数等
// 需要使用专门的库来解析文件内容
// ===== 文件类型校验结束 =====
// 上传文件
try {
// 获取到元数据后,使用元数据内的信息,上传文件到云存储
const metadata = await storage.getUploadMetadata(cloudPath);
const { authorization, token, cosFileId, url } = metadata;
// 构造提交表单
const form = new FormData();
form.append("Signature", authorization);
form.append("x-cos-security-token", token);
form.append("x-cos-meta-fileid", cosFileId);
form.append("key", cloudPath);
form.append("file", binaryData);
// 执行上传
await axios.post(url, form, { headers: form.getHeaders() });
return {
success: true,
result: "上传成功",
fileID: cosFileId
}
} catch (error) {
console.error("上传失败:", error);
return {
success: false,
result: "上传失败,请稍后重试"
}
}
};
1.3 文件类型校验说明
在上面的云函数中,我们实现了多种文件校验逻辑:
扩展名校验:通过检查文件扩展名,限制允许上传的文件类型
const ext = path.extname(fileName).toLowerCase();
const allowedExtensions = [".docx", ".pdf", ".jpg", ".png", ".xlsx"];
if (!allowedExtensions.includes(ext)) {
return { success: false, result: "文件类型不支持" }
}MIME类型校验:通过检查文件的MIME类型进行更严格的校验
const mimeType = file.split(";")[0].split(":")[1];
const allowedMimeTypes = [
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/pdf",
"image/jpeg",
"image/png",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
];
if (!allowedMimeTypes.includes(mimeType)) {
return { success: false, result: "文件MIME类型不支持" }
}文件大小校验:限制上传文件的大小
const fileSizeInBytes = binaryData.length;
const maxSizeInBytes = 10 * 1024 * 1024; // 10MB
if (fileSizeInBytes > maxSizeInBytes) {
return { success: false, result: "文件大小超过限制,最大支持10MB" }
}文件内容校验:对于特定类型的文件,可以进行内容校验,例如检查图片尺寸、文档页数等。这需要使用专门的库来解析文件内容。
2. APIs中定义此云函数
在微搭平台的APIs管理中,定义并发布此云函数:
3. 在组件中使用
3.1 新建Query
创建一个用于调用云函数的Query:
3.2 配置上传前处理函数
在上传组件的上传前处理函数中,不使用默认上传行为,改为query上传:
4. 最佳实践
- 安全性考虑:始终在服务端进行文件类型校验,不要仅依赖前端校验
- 错误处理:提供清晰的错误信息,帮助用户理解上传失败的原因
- 日志记录:记录上传失败的情况,便于问题排查
- 性能优化:对于大文件,考虑使用分片上传
- 用户体验:在上传前向用户展示允许的文件类型和大小限制