@zkrvndm
Софт для автоматизации

Как правильно составить тело запроса при multipart/form-data?

Хочу вручную отправить файл, пример части тела запроса:
Content-Disposition: form-data; name="myfile"; filename="pic.jpg"
Content-Type: image/jpeg
(пустая строка)
содержимое файла

Вместо содержимого файла, я пробовал подставить вывод как от reader.readAsText, так и от reader.readAsBinaryString, но увы, в обеих случаях я на стороне сервера получаю битый файл. Что это за загадочное содержимое файла о котором в документации ни слова? В какой кодировке я должен подствалять файл, если уж даже бинарная строка не подходит?
  • Вопрос задан
  • 986 просмотров
Решения вопроса 2
Alexandroppolus
@Alexandroppolus
кодир
https://learn.javascript.ru/formdata

или хочется именно вручную? Тогда самый простой вариант - через конструктор блоба
const body = new Blob(['some text', file, 'some text 2', ...]);

Вот такая штука просто берет и конкатенирует всё в один блоб, который ты просто отправляешь в fetch. При этом строки автоматом кодируются в utf8, а файлы просто копируют свои байты. Здесь строки - это текстовые значения формы, разделители и прочая служебная хрень, ну а файлы - это файлы, которые даже не надо читать ФайлРидером.
Ответ написан
@zkrvndm Автор вопроса
Софт для автоматизации
Благодоря подсказе 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;

}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@writer_2159
Жуть... просто жуть...
Вот прям из коробки есть вариант
const formData = new FormData();
formData.append('file', document.querySelector('input[type=file]').files[0]);

fetch('http:google.com', {
        body:formData,
        'POST',
    });


на стороне PHP принимается как $_FILES
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы