← Назад к вопросам
Как отправить файл в теле POST-запроса?
1.0 Junior🔥 191 комментариев
#Работа с сетью
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как отправить файл в теле POST-запроса?
Загрузка файлов — одна из самых частых операций в мобильных приложениях. Flutter предоставляет несколько способов для отправки файлов на сервер.
1. Использование http пакета с File
Простой способ отправки файла:
import 'package:http/http.dart' as http;
import 'dart:io';
Future<void> uploadFile(File file) async {
var request = http.MultipartRequest(
'POST',
Uri.parse('https://api.example.com/upload'),
);
// Добавляем файл
request.files.add(
await http.MultipartFile.fromPath(
'file', // Имя поля в форме
file.path,
),
);
// Добавляем дополнительные параметры если нужно
request.fields['description'] = 'My uploaded file';
request.fields['userId'] = '123';
try {
var response = await request.send();
if (response.statusCode == 200) {
print('Файл успешно загружен');
} else {
print('Ошибка: ${response.statusCode}');
}
} catch (e) {
print('Ошибка загрузки: $e');
}
}
2. Отправка файла как бинарные данные
Для отправки файла как содержимого POST-запроса:
import 'package:http/http.dart' as http;
import 'dart:io';
Future<void> uploadFileAsBinary(File file) async {
try {
// Читаем содержимое файла
List<int> fileBytes = await file.readAsBytes();
var response = await http.post(
Uri.parse('https://api.example.com/upload'),
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': 'Bearer token',
},
body: fileBytes,
);
if (response.statusCode == 200) {
print('Файл загружен успешно');
} else {
print('Ошибка: ${response.statusCode}');
}
} catch (e) {
print('Ошибка: $e');
}
}
3. Загрузка с отслеживанием прогресса
Используем dio пакет для отслеживания прогресса:
import 'package:dio/dio.dart';
import 'dart:io';
Future<void> uploadFileWithProgress(File file) async {
final dio = Dio();
try {
FormData formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
file.path,
filename: file.path.split('/').last,
),
'userId': '123',
});
Response response = await dio.post(
'https://api.example.com/upload',
data: formData,
onSendProgress: (int sent, int total) {
double progress = sent / total * 100;
print('Загрузка: $progress%');
},
);
if (response.statusCode == 200) {
print('Успешно');
}
} catch (e) {
print('Ошибка: $e');
}
}
4. Загрузка нескольких файлов
import 'package:http/http.dart' as http;
import 'dart:io';
Future<void> uploadMultipleFiles(List<File> files) async {
var request = http.MultipartRequest(
'POST',
Uri.parse('https://api.example.com/upload-multiple'),
);
// Добавляем несколько файлов
for (var file in files) {
request.files.add(
await http.MultipartFile.fromPath(
'files', // Одно имя для всех файлов
file.path,
),
);
}
try {
var response = await request.send();
if (response.statusCode == 200) {
var responseBody = await response.stream.bytesToString();
print('Ответ: $responseBody');
}
} catch (e) {
print('Ошибка: $e');
}
}
5. Выбор и загрузка файла с помощью file_picker
import 'package:file_picker/file_picker.dart';
import 'package:http/http.dart' as http;
import 'dart:io';
Future<void> pickAndUploadFile() async {
try {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.any,
allowMultiple: false,
);
if (result != null) {
File file = File(result.files.single.path!);
await uploadFile(file);
} else {
print('Пользователь отменил выбор файла');
}
} catch (e) {
print('Ошибка: $e');
}
}
6. JSON запрос с файлом в виде Base64
Для отправки файла как часть JSON:
import 'package:http/http.dart' as http;
import 'dart:io';
import 'dart:convert';
Future<void> uploadFileAsBase64(File file) async {
try {
// Читаем файл и кодируем в Base64
List<int> fileBytes = await file.readAsBytes();
String base64File = base64Encode(fileBytes);
Map<String, dynamic> payload = {
'file': base64File,
'fileName': file.path.split('/').last,
'userId': '123',
};
var response = await http.post(
Uri.parse('https://api.example.com/upload'),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token',
},
body: jsonEncode(payload),
);
if (response.statusCode == 200) {
print('Файл загружен');
}
} catch (e) {
print('Ошибка: $e');
}
}
7. Загрузка с обработкой ошибок и retry
import 'package:http/http.dart' as http;
import 'dart:io';
Future<void> uploadFileWithRetry(
File file, {
int maxRetries = 3,
}) async {
int retryCount = 0;
while (retryCount < maxRetries) {
try {
var request = http.MultipartRequest(
'POST',
Uri.parse('https://api.example.com/upload'),
);
request.files.add(
await http.MultipartFile.fromPath('file', file.path),
);
var response = await request.send().timeout(
Duration(seconds: 30),
onTimeout: () {
throw TimeoutException('Превышено время ожидания');
},
);
if (response.statusCode == 200) {
print('Файл успешно загружен');
return;
} else if (response.statusCode >= 500) {
// Ошибка сервера, пробуем снова
retryCount++;
print('Повтор попытки $retryCount...');
await Future.delayed(Duration(seconds: 2 * retryCount));
} else {
// Ошибка клиента, не повторяем
print('Ошибка клиента: ${response.statusCode}');
return;
}
} catch (e) {
retryCount++;
if (retryCount < maxRetries) {
print('Ошибка, повтор попытки $retryCount: $e');
await Future.delayed(Duration(seconds: 2 * retryCount));
} else {
print('Все попытки исчерпаны: $e');
}
}
}
}
Сравнение подходов
| Подход | Использование | Плюсы | Минусы |
|---|---|---|---|
| http + MultipartRequest | Стандартная загрузка | Встроенный пакет | Нет отслеживания прогресса |
| http + Binary | JSON API | Просто | Большие файлы медленнее |
| dio | Большие файлы | Прогресс, retry | Дополнительный пакет |
| Base64 + JSON | Маленькие файлы | Универсально | Медленнее, больший трафик |
Лучшие практики
1. Проверяйте размер файла:
const maxFileSize = 10 * 1024 * 1024; // 10 MB
if (file.lengthSync() > maxFileSize) {
print('Файл слишком большой');
return;
}
2. Используйте тайм-ауты:
var response = await request.send().timeout(
Duration(seconds: 60),
onTimeout: () => throw Exception('Timeout'),
);
3. Обрабатывайте ошибки сети:
try {
// загрузка
} on SocketException {
print('Нет интернета');
} on TimeoutException {
print('Превышено время');
} catch (e) {
print('Другая ошибка');
}
4. Показывайте прогресс пользователю: Используйте dio с onSendProgress для отслеживания загрузки и обновления UI через StreamBuilder или BLoC.