feat: 上传文件到minio
This commit is contained in:
@@ -5,6 +5,10 @@ import path from 'path';
|
||||
import { IncomingForm } from 'formidable';
|
||||
import { checkToken } from '@abearxiong/auth';
|
||||
import { useConfig } from '@abearxiong/use-config';
|
||||
import { minioClient } from '@/app.ts';
|
||||
import { bucketName } from '@/modules/minio.ts';
|
||||
import { getContentType } from '@/utils/get-content-type.ts';
|
||||
import { User } from '@/models/user.ts';
|
||||
const { tokenSecret } = useConfig<{ tokenSecret: string }>();
|
||||
const filePath = useFileStore('upload');
|
||||
// curl -X POST http://localhost:4000/api/upload -F "file=@readme.md"
|
||||
@@ -15,12 +19,12 @@ const filePath = useFileStore('upload');
|
||||
// -F "username=testuser"
|
||||
|
||||
export const uploadMiddleware = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||
if (req.method === 'GET' && req.url === '/api/upload') {
|
||||
if (req.method === 'GET' && req.url === '/api/app/upload') {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('Upload API is ready');
|
||||
return;
|
||||
}
|
||||
if (false && req.method === 'POST' && req.url === '/api/upload') {
|
||||
if (false && req.method === 'POST' && req.url === '/api/app/upload') {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
|
||||
// 检查 Content-Type 是否为 multipart/form-data
|
||||
@@ -78,61 +82,70 @@ export const uploadMiddleware = async (req: http.IncomingMessage, res: http.Serv
|
||||
res.end(uploadResults.join('\n'));
|
||||
});
|
||||
}
|
||||
if (req.method === 'POST' && req.url === '/api/upload') {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
const authroization = req.headers?.['Authorization'] as string;
|
||||
if (req.method === 'POST' && req.url === '/api/app/upload') {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
const authroization = req.headers?.['authorization'] as string;
|
||||
const error = (msg: string) => {
|
||||
return JSON.stringify({ code: 500, message: msg });
|
||||
};
|
||||
if (!authroization) {
|
||||
res.statusCode = 401;
|
||||
res.end('Invalid authorization');
|
||||
res.end(error('Invalid authorization'));
|
||||
return;
|
||||
}
|
||||
const token = authroization.split(' ')[1];
|
||||
const tokenUser = await checkToken(token, tokenSecret);
|
||||
if (!tokenUser) {
|
||||
let tokenUser;
|
||||
try {
|
||||
tokenUser = await User.verifyToken(token);
|
||||
} catch (e) {
|
||||
res.statusCode = 401;
|
||||
res.end('Invalid token');
|
||||
res.end(error('Invalid token'));
|
||||
return;
|
||||
}
|
||||
//
|
||||
//
|
||||
// 使用 formidable 解析 multipart/form-data
|
||||
const form = new IncomingForm({
|
||||
multiples: true, // 支持多文件上传
|
||||
uploadDir: filePath, // 上传文件存储目录
|
||||
});
|
||||
// 解析上传的文件
|
||||
form.parse(req, (err, fields, files) => {
|
||||
form.parse(req, async (err, fields, files) => {
|
||||
if (err) {
|
||||
res.end(`Upload error: ${err.message}`);
|
||||
res.end(error(`Upload error: ${err.message}`));
|
||||
return;
|
||||
}
|
||||
console.log('fields', fields);
|
||||
const { appKey, version } = fields;
|
||||
// 逐个处理每个上传的文件
|
||||
const uploadedFiles = Array.isArray(files.file) ? files.file : [files.file];
|
||||
const uploadResults = [];
|
||||
|
||||
uploadedFiles.forEach((file) => {
|
||||
for (let i = 0; i < uploadedFiles.length; i++) {
|
||||
const file = uploadedFiles[i];
|
||||
// @ts-ignore
|
||||
const tempPath = file.filepath; // 文件上传时的临时路径
|
||||
const relativePath = file.originalFilename; // 保留表单中上传的文件名 (包含文件夹结构)
|
||||
uploadResults.push(`File ${relativePath} uploaded successfully. ${tempPath}`);
|
||||
// 比如 child2/b.txt
|
||||
const minioPath = `${tokenUser.username}/${appKey}/${version}/${relativePath}`;
|
||||
// 上传到 MinIO 并保留文件夹结构
|
||||
// minioClient.fPutObject(bucketName, relativePath, tempPath, {}, (err, etag) => {
|
||||
// fs.unlinkSync(tempPath); // 删除临时文件
|
||||
|
||||
// if (err) {
|
||||
// uploadResults.push(`Upload error for ${relativePath}: ${err.message}`);
|
||||
// } else {
|
||||
// uploadResults.push(`File ${relativePath} uploaded successfully. ETag: ${etag}`);
|
||||
// }
|
||||
|
||||
// // 如果所有文件都处理完毕,返回结果
|
||||
// if (uploadResults.length === uploadedFiles.length) {
|
||||
// res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
// res.end(uploadResults.join('\n'));
|
||||
// }
|
||||
// });
|
||||
});
|
||||
res.end(uploadResults.join('\n'));
|
||||
const isHTML = relativePath.endsWith('.html');
|
||||
await minioClient.fPutObject(bucketName, minioPath, tempPath, {
|
||||
'Content-Type': getContentType(relativePath),
|
||||
'app-source': 'user-app',
|
||||
'Cache-Control': isHTML ? 'no-cache' : 'max-age=31536000, immutable', // 缓存一年
|
||||
});
|
||||
uploadResults.push({
|
||||
name: relativePath,
|
||||
path: minioPath,
|
||||
});
|
||||
fs.unlinkSync(tempPath); // 删除临时文件
|
||||
}
|
||||
// 修改header
|
||||
// res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
const data = {
|
||||
code: 200,
|
||||
data: uploadResults,
|
||||
};
|
||||
res.end(JSON.stringify(data));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user