You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Dio发送FormData至Laravel无数据接收问题排查

问题描述

基于Dio库开发API Client时遇到如下问题:仅发送文本字段时,使用Map或Object格式可被Laravel正常接收;但发送文件时使用FormData格式,Laravel无法读取到任何请求数据。

相关代码

请求体处理方法

Future<dynamic> _processRequestBody(dynamic body) async {
    if (body == null) return null;

    if (body is! Map<String, dynamic>) return body;

    bool hasFiles = false;
    final formMap = <String, dynamic>{};

    Future<List<MultipartFile>> processMultipleFiles(List<PlatformFile> files) async {
      return Future.wait(files.map((file) => MultipartFile.fromFile(
        file.path!,
        filename: file.name,
      )));
    }

    Future<MultipartFile> processSingleFile(PlatformFile file) async {
      return MultipartFile.fromFile(
        file.path!,
        filename: file.name,
      );
    }

    for (var entry in body.entries) {
      final value = entry.value;

      try {
        if (value is List<PlatformFile>) {
          hasFiles = true;
          if (value.length == 1) {
            formMap[entry.key] = await processSingleFile(value.first);
          } else {
            formMap[entry.key] = await processMultipleFiles(value);
          }
        } else if (value is PlatformFile) {
          hasFiles = true;
          formMap[entry.key] = await processSingleFile(value);
        } else if (value != null) {
          formMap[entry.key] = value.toString();
        }
      } catch (e) {
        print('Error processing field ${entry.key}: $e');
        rethrow;
      }
    }

    print(formMap);
    return hasFiles ? FormData.fromMap(formMap) : body;
}

PUT请求处理

Future<Response> put(
      String path, {
        dynamic body,
        Map<String, dynamic>? queryParameters,
        Options? options,
        bool unusedAuth = false,
      }) async {
    try {
      final requestOptions = options ?? Options();
      requestOptions.extra = {
        ...requestOptions.extra ?? {},
        'unusedAuth': unusedAuth,
      };

      final processedBody = await _processRequestBody(body);

      if (processedBody is FormData) {
        requestOptions.headers = {
          ...requestOptions.headers ?? {},
          'Content-Type': 'multipart/form-data',
        };
      }

      final response = await _dio.put(
        path,
        data: processedBody,
        queryParameters: queryParameters,
        options: requestOptions,
      );
      return response;
    } on DioException catch (e) {
      throw _handleError(e);
    }
}

API调用示例

Future<BaseResponse> updateProfile(UserProfileData formData) async {
      final response = await _apiClient.put(
        ApiPath.updateProfile,
        body: formData.toJson(),
      );
}

Laravel后端代码

public function editProfileUser(Request $request)
{
    \Log::info('All request data:', $request->all());
    \Log::info('Files:', $request->allFiles());
    \Log::info('Has file test:', [
        'hasFile' => $request->hasFile('your_file_field_name'),
        'files' => $request->files->all()
    ]);

    return $this->response(500, "Error", null);
}

日志结果

[2024-11-03 00:01:04] local.INFO: All request data:  
[2024-11-03 00:01:04] local.INFO: Files:
[2024-11-03 00:01:04] local.INFO: Has file test: {"hasFile":false,"files":[]}

环境信息

  • Laravel版本:10.48.22
  • Flutter版本:3.24.0
  • Dio版本:^5.7.0
  • 文件类型:List<PlatformFile>

咨询问题

  • 问题出在Flutter端还是Laravel端?
  • 需要修复哪些内容?
  • 两端是否有特殊配置要求?

解决方案

  1. 问题定位:问题出在Flutter端,核心原因是手动设置Content-Type的方式错误,导致Laravel无法正确解析multipart/form-data请求。
  2. 修复内容:
    • 移除手动设置的Content-Type:Dio在处理FormData时会自动生成包含boundary分隔符的正确Content-Type头,手动设置'multipart/form-data'会覆盖这个自动生成的头,缺少boundary的情况下Laravel无法解析表单数据。修改PUT请求处理代码,删除以下片段:
      if (processedBody is FormData) {
        requestOptions.headers = {
          ...requestOptions.headers ?? {},
          'Content-Type': 'multipart/form-data',
        };
      }
      
    • 优化非文件字段处理:不要强制将非文件字段转为字符串,保留原始类型(如数字、布尔值),Dio会自动处理序列化。将请求体处理方法中的formMap[entry.key] = value.toString();改为formMap[entry.key] = value;。
    • 校验文件路径有效性:确保PlatformFile的path不为null,可在处理文件前添加非空判断,避免因文件路径无效导致FormData构造失败。
  3. 两端配置要求:
    • Flutter端:无需额外配置,确保Dio版本正确;文件选择后需确认PlatformFile的路径可访问(Android需申请文件读取权限,iOS需确保文件在沙箱可访问范围内)。
    • Laravel端:无需特殊配置,Laravel 10默认支持multipart/form-data解析;确保API路由使用PUT方法,且未被CSRF中间件拦截(API路由组默认已排除CSRF验证)。

内容的提问来源于stack exchange,提问作者account Incognito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:19:51