Flutter实现FormData格式POST请求及图片上传问题(附JS示例)
Got it, let's walk through how to replicate your JavaScript FormData image upload functionality in Flutter. We'll use the http package (Flutter's go-to for HTTP requests) to handle multipart/form-data, mirror your hostname-based URL logic, and handle credentials just like xhr.withCredentials = true.
Step 1: Add the http dependency
First, make sure you have the http package in your pubspec.yaml:
dependencies: flutter: sdk: flutter http: ^1.1.0 # Use the latest version available
Run flutter pub get to install it.
Step 2: Replicate the hostname-based URL logic
In your JS code, you dynamically build the upload URL based on the current hostname. For Flutter web, you can grab the current hostname using dart:html; for mobile, you might use app-configured constants or pass the hostname as a parameter. Here's the mirrored logic:
import 'dart:html' as html; // Only for web targets String buildUploadUrl(String uploadpoint) { final hostname = html.window.location.hostname; final protocol = html.window.location.protocol; if (hostname == "localhost") { return "http://localhost:9999/$uploadpoint"; } else if (hostname == "www.aladin.finance") { return "$protocol//uploadfile.aladin.finance/$uploadpoint"; } else { return "$protocol//uploadfile.$hostname/$uploadpoint"; } }
Note: For mobile apps, replace the hostname/protocol retrieval with your app's environment config (e.g., from a constants file or .env setup).
Step 3: Build the MultipartRequest (equivalent to FormData)
Flutter's MultipartRequest is the direct stand-in for JavaScript's FormData. We'll add your parameters (session, fileindex) and the image file to it. The code below supports both web and mobile file sources:
import 'package:http/http.dart' as http; import 'dart:io'; // For mobile File import 'dart:html' as html; // For web File import 'package:http_parser/http_parser.dart'; // For MediaType Future<void> uploadImage({ required dynamic imageFile, // html.File for web, File for mobile required String sessionId, required int fileListIndex, required String uploadpoint, }) async { // Build the target upload URL final url = buildUploadUrl(uploadpoint); // Initialize multipart request final request = http.MultipartRequest('POST', Uri.parse(url)); // Add text parameters (matches formData.append) request.fields['session'] = sessionId; request.fields['fileindex'] = fileListIndex.toString(); // Add the image file to the request if (imageFile is html.File) { // Handle web file: convert html.File to bytes for MultipartFile final reader = html.FileReader(); await reader.readAsArrayBuffer(imageFile); final bytes = reader.result as List<int>; request.files.add(http.MultipartFile.fromBytes( 'file', bytes, filename: imageFile.name, contentType: MediaType.parse(imageFile.type), )); } else if (imageFile is File) { // Handle mobile file: add directly from device path request.files.add(await http.MultipartFile.fromPath( 'file', imageFile.path, filename: imageFile.path.split('/').last, )); } // Handle credentials (equivalent to xhr.withCredentials = true) // For web: Ensure cross-origin requests allow credentials (server must also set Access-Control-Allow-Credentials: true) request.headers['Access-Control-Allow-Credentials'] = 'true'; // For mobile: To persist cookies across requests, use a package like `cookie_jar` with a custom http.Client // Example: // final cookieJar = CookieJar(); // final client = http.Client(); // client.interceptors.add(CookieManager(cookieJar)); // final response = await client.send(request); // Send the request and handle response try { final response = await request.send(); if (response.statusCode == 200) { print('Upload successful!'); final responseBody = await response.stream.bytesToString(); print('Server response: $responseBody'); // Add your success handling logic here } else { print('Upload failed with status code: ${response.statusCode}'); // Add error handling logic here } } catch (e) { print('Upload error: $e'); } }
Key Details to Match Your JS Logic:
- FormData Equivalent:
request.fieldshandles text parameters, whilerequest.filesmanages file uploads, just likeformData.appendin JS. - WithCredentials: On web, setting
Access-Control-Allow-Credentialsin headers ensures cookies are sent with cross-origin requests (your server must also allow this). On mobile, use a cookie management package likecookie_jarto persist session cookies across requests. - Dynamic URL: The
buildUploadUrlfunction mirrors your JS logic for targeting different upload endpoints based on hostname.
内容的提问来源于stack exchange,提问作者Khôi Trần Quang

