开发者社区 > 云存储 > 对象存储OSS > 正文

flutter使用http库进行post请求文件上传返回400

已解决

通过后台获取到policy信息之后进行文件上传,结果使用http库一直提示400

使用postman或者apifox都可以上传成功

Future<String?> uplaodFile({required File file}) async {
  // 获取policy信息
    final ossPolicy = await getOSSPolicy(filename: path.basename(file.path));
    if (ossPolicy == null) {
      return null;
    }

    // Content-type
    final type = mime(path.basename(file.path))?.split("/").first;
    final subtype = mime(path.basename(file.path))?.split("/").last;

    // Form-data
    var request =
        http.MultipartRequest("POST", Uri.parse(ossPolicy.host ?? ossUrl))
          ..fields["OSSAccessKeyId"] = ossPolicy.accessKeyId ?? ""
          ..fields["Signature"] = ossPolicy.signature ?? ""
          ..fields["policy"] = ossPolicy.policy ?? ""
          ..fields["key"] = ossPolicy.fileId.toKey()
          ..fields["success_action_status"] = "200"
          ..files.add(await http.MultipartFile.fromPath('file', file.path,
        contentType: MediaType(type ?? "text", subtype ?? "plain")));

    final response = await request.send();

    if (response.statusCode != 200) {
      logger.e(await response.stream.bytesToString());

      return null;
    }

    return ossPolicy.fileId;
  }

请求返回结果:

I/flutter (13104): │ ⛔ <?xml version="1.0" encoding="UTF-8"?>
I/flutter (13104): │ ⛔ <Error>
I/flutter (13104): │ ⛔   <Code>MalformedPOSTRequest</Code>
I/flutter (13104): │ ⛔   <Message>The body of your POST request is not well-formed multipart/form-data</Message>
I/flutter (13104): │ ⛔   <RequestId>65C0AFBC84CC8A3733DFF7C4</RequestId>
I/flutter (13104): │ ⛔   <HostId>oss.*****.com</HostId>
I/flutter (13104): │ ⛔   <EC>0006-00000109</EC>
I/flutter (13104): │ ⛔   <RecommendDoc>https://api.aliyun.com/troubleshoot?q=0006-00000109</RecommendDoc>
I/flutter (13104): │ ⛔ </Error>
I/flutter (13104): │ ⛔

网上查看说是PostObject请求中表单域格式不正确
那这该如何修改???

展开
收起
1380076950386985 2024-02-05 18:02:10 127 0
2 条回答
写回答
取消 提交回答
  • 采纳回答

    根据错误信息The body of your POST request is not well-formed multipart/form-data,问题可能出在MultipartFormData的构造上。确保您正确设置了所有必需的表单字段和文件,并且格式符合OSS服务的要求。

    您可以尝试以下修改后的代码:

    import 'package:http/http.dart' as http;
    import 'dart:convert';
    import 'package:mime_type/mime_type.dart';
    
    Future<String?> uploadFile({required File file}) async {
      // 获取policy信息
      final ossPolicy = await getOSSPolicy(filename: path.basename(file.path));
      if (ossPolicy == null) {
        return null;
      }
    
      // Content-type
      final type = mime(path.basename(file.path))?.type;
    
      // Form-data
      var request = http.MultipartRequest("POST", Uri.parse(ossPolicy.host ?? ossUrl))
        ..headers.addAll({
          'Content-Type': 'multipart/form-data',
        })
        ..fields.addAll({
          'OSSAccessKeyId': ossPolicy.accessKeyId ?? '',
          'Signature': ossPolicy.signature ?? '',
          'policy': base64Encode(utf8.encode(ossPolicy.policy ?? '')),
          'key': ossPolicy.fileId.toKey(),
          'success_action_status': '200',
        })
        ..files.add(await http.MultipartFile.fromPath(
          'file',
          file.path,
          contentType: MediaType(type),
        ));
    
      final response = await request.send();
    
      if (response.statusCode != 200) {
        logger.e(await response.stream.bytesToString());
    
        return null;
      }
    
      return ossPolicy.fileId;
    }
    

    这里做了一些调整:

    1. policy字段值转换为Base64编码,因为有时候policy可能包含特殊字符,需要进行URL安全的Base64编码。
    2. 添加了Content-Type头,虽然http库会自动处理这个,但有时明确设置可能会解决问题。
    3. 确保contentType属性直接使用mime库获取到的类型。

    请检查并确认您的getOSSPolicy函数返回的policy是否需要Base64编码,如果不需要,请恢复原样。同时,请确保其他字段(如accessKeyId、signature等)的格式与后端要求一致。

    2024-02-05 23:48:05
    赞同 展开评论 打赏
  • 阿里云oss明确要求form请求开头必须是以Content-Disposition: form-data; name="*"开头,而在上传文件的时候,http库在添加_headerForFile方法的时候,将Content-Type: ${file.contentType}放在了Content-Disposition之前,所以导致oss认为请求格式不正确,修改他们的位置顺序之后请求就回复正常了。

    修改之前:

    /// Returns the header string for a file.
      ///
      /// The return value is guaranteed to contain only ASCII characters.
      String _headerForFile(MultipartFile file) {
        var header = 'Content-Type: ${file.contentType}\r\n'
            'Content-Disposition: form-data; name="${_browserEncode(file.field)}"';
    
        if (file.filename != null) {
          header = '$header; filename="${_browserEncode(file.filename!)}"';
        }
        return '$header\r\n\r\n';
      }
    

    修改之后:

    /// Returns the header string for a file.
      ///
      /// The return value is guaranteed to contain only ASCII characters.
      String _headerForFile(MultipartFile file) {
        var header =
            'Content-Disposition: form-data; name="${_browserEncode(file.field)}"\r\n'
            'Content-Type: ${file.contentType}';
    
        if (file.filename != null) {
          header = '$header; filename="${_browserEncode(file.filename!)}"';
        }
        return '$header\r\n\r\n';
      }
    
    2024-02-06 11:53:06
    赞同 展开评论 打赏

热门讨论

热门文章

相关电子书

更多
Flutter 应用框架 Fish-Redux 立即下载
基于flutter的产品应用实践 立即下载
《Flutter in action》 立即下载