Благодоря подсказе
Alexandroppolus наконец удалось правильно собрать тело запроса, теперь все работает =)
Пример ручной отправки файлов на сервер для будущих поколений:
// Тестовый объект:
test_obj = {
'per1': 'Привет!',
'per2': 'Это проверка!',
'per3': new File(['Привет, мир!'], 'test.txt', {type: 'text/plain'})
};
// Тестовая отправка:
await multipartSend(test_obj);
// Функция для отправки данных:
async function multipartSend(obj) {
// Генерируем уникальный разделитель:
var boundary = '----WebKitFormBoundary';
var symbols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < 18; i++) { boundary += symbols.charAt(Math.floor(Math.random() * symbols.length)); }
var arr = [ ]; // Массив для записи тела запроса
// Перебираем свойства отправляемого объекта:
for (key in obj) {
// Если текущее свойство объекта строка или число:
if (typeof obj[key] == 'string' || typeof obj[key] == 'number') {
// Добавляем значение текущего параметра в массив как строку, разумеется вместе с разделителем и метаданными:
arr.push("--" + boundary + "\r\nContent-Disposition: form-data; name=\"" + key + "\"\r\n\r\n" + obj[key] + "\r\n");
}
// Если текущее свойство объекта файл:
else if (typeof obj[key] == 'object') {
if (typeof obj[key]['name'] !== 'undefined' && typeof obj[key]['type'] !== 'undefined') {
// Добавляем метаданные от файла и разделитель, как обычную строку:
arr.push("--" + boundary + "\r\nContent-Disposition: form-data; name=\"" + key.replace(/\[[0-9]*\]$/, '[]') + "\"; filename=\"" + obj[key]['name'] + "\"\r\nContent-Type: " + obj[key]['type'] + "\r\n\r\n");
arr.push(obj[key]); // Сам файл добавляем целиком, как есть
arr.push("\r\n"); // И не забываем про перенос строкки с конца
}
}
}
arr.push("--" + boundary + "--\r\n"); // Добавляем последний разделитель в массив
var body = new Blob(arr); // Формируем тело запроса (бинарник) для отправки из собранного ранее массива
// Отправляем бинарник и смотрим результат:
var response = await (await fetch('https://nadim.work/test.php', {
'method': 'POST',
'headers': {
'Content-Type': 'multipart/form-data; boundary=' + boundary
},
'body': body
})).text();
console.log(response);
return response;
}