Загрузка нескольких файловых объектов в API в виде массива файлов 2d
Я пытаюсь создать API с помощью django, который поддерживает загрузку файлов в виде массива массивов. Пример того, чего я пытаюсь достичь, следующий:
[
{
"string": "Some string",
"files": [
"<uploaded file object 1>",
"<uploaded file object 2>"
]
},
{
"string": "Some string",
"files": [
"<uploaded file object 3>"
]
},
{
"string": "Some string",
"files": []
}
]
Я не хочу использовать для этого файлы в кодировке base64, так как файлы могут быть иногда большими, и я не хочу увеличивать накладные расходы, используя base64.
**Как я могу достичь этого вызова API наиболее эффективным способом, и какая структура будет наиболее подходящей для вызова этого API, и помогите с некоторым кодом javascript фронтенда для этого. **
Я попытался переместить это в FormData, где я могу достичь загрузки, как показано ниже, но я не могу вызвать API из фронтенда, это не работает, возможно, потому что я пишу неправильный код.
strings: ["Some string", "Some string", "Some string"]
files: [["<uploaded file object 1>", "<uploaded file object 2>"], ["<uploaded file object 3>"]]
Для бэкенда я использую django (rest framework), вот соответствующая часть сериализатора, если требуется
class StringSerializer(serializers.Serializer):
serializers = serializers.ListField(child=serializers.CharField())
files = serializers.ListField(
child=serializers.ListField(child=serializers.FileField()),
write_only=True,
required=False,
allow_empty=True,
default=[],
)
Примеры кодов с использованием FormData, Frontend и Backend (express)
Основные моменты кодирования фронтенда:
a. Для представления содержимого файла был создан объект blob. Обратитесь к утверждению: stmt-1.
b. Строка свойств была использована для установки ключа в объекте FormData.
c. Каждый объект blob в массиве был добавлен в formData по отдельности.
Для обоих вышеприведенных пунктов обратитесь к утверждению: stmt-2.
d. API был вызван внутри хука useEffect. Обратитесь к утверждению: stmt-3.
e. Статус загрузки был обновлен в переменной state. Обратитесь к утверждению: stmt-4.
App.js
import { useEffect, useState } from 'react';
export default function App() {
const [uploadStatus, setUploadStatus] = useState('');
const someContent = '<q id="a"><span id="b">hey!</span></q>';
const blob = new Blob([someContent], { type: 'text/xml' }); // stmt 1
const data = [
{
string: 'Somestring1',
files: [blob, blob],
},
{
string: 'Somestring2',
files: [blob],
},
{
string: 'Somestring3',
files: [blob],
},
];
const formData = new FormData();
data.forEach((rec) => {
rec.files.forEach((file) => {
formData.append(rec.string, file); // stmt-2
});
});
useEffect(() => {
fetch('http://localhost:3001/api/upload', {
method: 'POST',
body: formData,
})
.then((response) => response.text())
.then((data) => setUploadStatus(data)); // stmt-4
}, []); // stmt-3
return 'Upload Status : ' + (uploadStatus ? uploadStatus : 'Unknown');
}
Бэкенд - Express с использованием multer middleware
Основные моменты кодирования
a. Код multipart-formdata во фронтенде был получен nodejs middleware multer. Подробнее о multer, смотрите на странице https://www.npmjs.com/package/multer.
server.js
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const upload = multer({
dest: 'uploads',
});
const app = express();
app.use(cors());
app.post('/api/upload', upload.any(), (req, res, next) => {
console.log(req.files);
res.send('success');
});
app.listen(3001, () => {
console.log('Listening...');
});
Пробный запуск:
При выполнении кода фронтенда файлы будут загружены автоматически, а на внутреннем сервере будут созданы журналы консоли сервера, как показано ниже.
[
{
fieldname: 'Somestring1',
originalname: 'blob',
encoding: '7bit',
mimetype: 'text/xml',
destination: 'uploads',
filename: 'f94460f91f497bac0c1e0fdc4292eadc',
path: 'uploads/f94460f91f497bac0c1e0fdc4292eadc',
size: 38
},
{
fieldname: 'Somestring1',
originalname: 'blob',
encoding: '7bit',
mimetype: 'text/xml',
destination: 'uploads',
filename: 'deb237a854b4027a9e106effc236343d',
path: 'uploads/deb237a854b4027a9e106effc236343d',
size: 38
},
{
fieldname: 'Somestring2',
originalname: 'blob',
encoding: '7bit',
mimetype: 'text/xml',
destination: 'uploads',
filename: '52fd4e96f278f216f339be0f72ce1b6f',
path: 'uploads/52fd4e96f278f216f339be0f72ce1b6f',
size: 38
},
{
fieldname: 'Somestring3',
originalname: 'blob',
encoding: '7bit',
mimetype: 'text/xml',
destination: 'uploads',
filename: '781e6d3bbf3fb01149fa7fd8e428339d',
path: 'uploads/781e6d3bbf3fb01149fa7fd8e428339d',
size: 38
}
]
В папке uploads в бэкенде будут храниться загруженные файлы. Их список приведен ниже.