【问题标题】:How make a http post using form data in flutter?如何在颤振中使用表单数据制作 http 帖子?
【发布时间】:2020-01-10 18:15:04
【问题描述】:

我正在尝试执行 http post 请求,我需要将正文指定为 form-data,因为服务器不会将请求视为原始请求。

这就是我正在做的:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  postTest() async {
    final uri = 'https://na57.salesforce.com/services/oauth2/token';
    var requestBody = {
      'grant_type':'password',
      'client_id':'3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL',
      'client_secret':'42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42',
      'username':'example@mail.com.us',
      'password':'ABC1234563Af88jesKxPLVirJRW8wXvj3D'
    };

    http.Response response = await http.post(
        uri,
        body: json.encode(requestBody),
    );

    print(response.body);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Container(
        child: Center(
          child: RaisedButton(
            child: Text('Press Here'),
            onPressed: (){
              postTest();
            },
          ),
        ),
      ),
    );
  }
}

这是实际的响应:

{
    "error": "unsupported_grant_type",
    "error_description": "grant type not supported"
}

这是预期的响应:

{
    "access_token": "00D0b000000Bb08!AR8AQO.s8mAGXCbwV77FXNLQqc2vtl8g6_16miVbgWlQMsuNHsaf2IGLUwnMVXBOfAj19iznhqhwlPOi4tagvf7FFgiJJgoi",
    "instance_url": "https://na57.salesforce.com",
    "id": "https://login.salesforce.com/id/00D0b000000Bb08EAC/0050b000005nstiAAA",
    "token_type": "Bearer",
    "issued_at": "1567993324968",
    "signature": "1+Zd/dSh9i7Moh2U0nFJLdXkVHqPlPVU6emwdYzXDPk="
}

您可以在 postman 在 raw(得到实际响应)和 form-data(得到预期响应)之间切换正文进行测试

PS:标头是客户端工具创建的临时标头。

【问题讨论】:

  • 你找到相同的解决方案了吗?请分享
  • 有什么解决办法吗?来自@MalithKuruwita 的上述链接也没有被接受的答案
  • @EightRice 如果您想将数据发送到接受内容类型的服务器:x-www-form-urlencoded,我提供的上述 URL 有效。它适用于文本数据。但是如果你想发送多部分/表单数据。像文件或图像到服务器(二进制数据),使用它(developerlibs.com/2020/07/…)。该博客还展示了如何发送文本数据。根据服务器接受的内容类型使用相关的

标签: http flutter dart form-data


【解决方案1】:

您也可以使用 MultiPartRequest,它肯定会工作

  var request = new 
  http.MultipartRequest("POST",Uri.parse("$baseUrl/example/"));

  request.headers.addAll(baseHeader);
  request.fields['id'] = params.id.toString();
  request.fields['regionId'] = params.regionId.toString();
  request.fields['districtId'] = params.districtId.toString(); 
  http.Response response = await http.Response.fromStream(await 
  request.send());

  print('Uploaded! ${response.body} ++ ${response.statusCode}');
 

【讨论】:

    【解决方案2】:

    此代码 sn-ps 成功执行 POST api 调用,该调用需要授权令牌和表单数据。

    final headers = {'Authorization': 'Bearer $authToken'};
      var requestBody = {
        'shopId': '5',
        'fromDate': '01/01/2021',
        'toDate': '01/10/2022',
      };
    
      final response = await http.post(
        Uri.parse(
            'https://api.sample.com/mobile/dashboard/getdetails'),
        headers: headers,
        body: requestBody,
      );
    
      print("RESPONSE ${response.body}");
    

    【讨论】:

      【解决方案3】:

      HTTP 还不支持form-data

      请改用DIO。它会自己处理一切!

      【讨论】:

        【解决方案4】:

        那么,您想将正文作为表单数据发送,对吗?也许你可以试试这个?对我来说这是工作

        postTest() async {
            final uri = 'https://na57.salesforce.com/services/oauth2/token';
            var requestBody = {
              'grant_type':'password',
              'client_id':'3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL',
              'client_secret':'42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42',
              'username':'example@mail.com.us',
              'password':'ABC1234563Af88jesKxPLVirJRW8wXvj3D'
            };
        
            http.Response response = await http.post(
                uri,
                body: requestBody,
            );
        
            print(response.body);
          }
        

        或者

        postTest() async {
            final uri = 'https://na57.salesforce.com/services/oauth2/token';
        
            http.Response response = await http.post(
                uri, body: {
              'grant_type':'password',
              'client_id':'3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL',
              'client_secret':'42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42',
              'username':'example@mail.com.us',
              'password':'ABC1234563Af88jesKxPLVirJRW8wXvj3D'
            });
        
            print(response.body);
          }
        

        【讨论】:

          【解决方案5】:

          使用 MultipartRequest 类

          multipart/form-data 请求会自动将 Content-Type 标头设置为 multipart/form-data。

          此值将覆盖用户设置的任何值。

          参考 pub.dev 文档here

          例如:

           Map<String, String> requestBody = <String,String>{
               'field1':value1
            };
           Map<String, String> headers= <String,String>{
               'Authorization':'Basic ${base64Encode(utf8.encode('user:password'))}'
            };
          
            var uri = Uri.parse('http://localhost.com');
            var request = http.MultipartRequest('POST', uri)
              ..headers.addAll(headers) //if u have headers, basic auth, token bearer... Else remove line
              ..fields.addAll(requestBody);
            var response = await request.send();
            final respStr = await response.stream.bytesToString();
            return jsonDecode(respStr);
          

          希望对你有帮助

          【讨论】:

          • 如果有人像我一样想知道,您可以使用await http.Response.fromStream(streamedResponse) 从流式响应中获取通常的响应对象
          【解决方案6】:

          使用 POSTMAN 测试查询并获取格式非常有用。这允许您查看是否真的需要设置标头。请参阅下面的示例。我希望它有所帮助,而且不要太多

          import 'dart:convert';
          import 'package:http/http.dart';
          
          class RegisterUser{    
            String fullname;
            String phonenumber;
            String emailaddress;
            String password;
            Map data;    
            RegisterUser({this.fullname, this.phonenumber, this.emailaddress, this.password});    
            Future<void> registeruseraction() async {    
              String url = 'https://api.url.com/';
              Response response = await post(url, body: {
                'fullname' : fullname,
                'phonenumber' : phonenumber,
                'emailaddress' : emailaddress,
                'password' : password
              });    
              print(response.body);
              data = jsonDecode(response.body);    
            }    
          }
          

          【讨论】:

            【解决方案7】:

            有一个dart包dio
            它就像一个魅力,我用它作为标准来做 http 请求。
            请阅读docs 也可以使用 dio 包发送表单数据

            import 'package:dio/dio.dart';    
            
            postData(Map<String, dynamic> body)async{    
            var dio = Dio();
            try {
                  FormData formData = new FormData.fromMap(body);
                  var response = await dio.post(url, data: formData);
                  return response.data;
                } catch (e) {
                  print(e);
                }
            }
            

            【讨论】:

            • 在 Map 中没有参数时从哪里获取 url
            • 那是一段代码。希望能得到想要的答案
            【解决方案8】:

            编辑 1(这适用于代码登录流程):

            String url = "https://login.salesforce.com/services/oauth2/token";
            http.post(url, body: {
              "grant_type": "authorization_code",
              "client_id": "some_client_id",
              "redirect_uri": "some_redirect_uri",
              "code": "some_code_generated_by_salesforce_login",
              "client_secret": "some_client_secret",
            }).then((response) {
              //--handle response
            });
            

            试一试“FormData”:

            import 'package:dio/dio.dart';
            
            FormData formData = new FormData.fromMap(dataMap);
            
            retrofitClient.getToken(formData).then((response){//--handle respnse--});
            

            'retrofitClient' 来自包 改造:^1.0.1+1

            【讨论】:

            • 无效的请求正文 \"Instance of 'FormData'\".
            【解决方案9】:

            改为使用 Map,因为 http 包中的 body 只有 3 种类型:String、List 或 Map。试试这个:

            final uri = 'https://na57.salesforce.com/services/oauth2/token';
            var map = new Map<String, dynamic>();
            map['grant_type'] = 'password';
            map['client_id'] = '3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL';
            map['client_secret'] = '42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42';
            map['username'] = 'example@mail.com.us';
            map['password'] = 'ABC1234563Af88jesKxPLVirJRW8wXvj3D';
            
            http.Response response = await http.post(
                uri,
                body: map,
            );
            

            【讨论】:

            • 没用,post 方法仍然接受使用 json 对象
            • 如果 body 是一个 Map,它被编码为使用编码的表单字段。请求的内容类型将设置为“application/x-www-form-urlencoded”。 pub.dev/documentation/http/latest/http/Client/post.html
            • 似乎使用 Map 的行为更像是来自 HTML 表单的帖子,而不是官方 Flutter 文档中使用的 jsonEncode 方法。谢谢。修复了我的问题。
            • 地图对我不起作用。我必须使用 Dio FormData,但我想知道为什么发送地图会收到 400 错误?
            • @mohammad 你发了什么?
            【解决方案10】:

            你可以试试这个吗?

                String url = 'https://myendpoint.com';
                  Map<String, String> headers = {
            "Content-Type": "application/x-www-form-urlencoded"    
            "Content-type": "application/json"};
                  String json = '{"grant_type":"password",
                    "username":"myuser@mail.com",
                    "password":"123456"}';
                  // make POST request
                  Response response = await post(url, headers: headers, body: json);
                  // check the status code for the result
                  int statusCode = response.statusCode;
                  // this API passes back the id of the new item added to the body
                  String body = response.body;
            

            【讨论】:

            • 使用或不使用标题没有区别,我的意思是如何将正文作为表单数据发送
            • 我也更新了我的问题,现在你可以测试更接近我真实情况的东西了。
            • @M.Massula 我认为在颤振中,没有任何选项可以请求使用表单数据。这是可能的,您可以使用 json 传递数据。
            • 这在标题字符串之间缺少逗号。
            猜你喜欢
            • 2020-02-17
            • 1970-01-01
            • 2021-01-26
            • 2021-08-01
            • 2020-10-13
            • 1970-01-01
            • 1970-01-01
            • 2019-01-30
            • 2022-11-03
            相关资源
            最近更新 更多