如何在颤振中使用表单数据制作 http 帖子?

Posted

技术标签:

【中文标题】如何在颤振中使用表单数据制作 http 帖子?【英文标题】:How make a http post using form data in flutter? 【发布时间】: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:标头是客户端工具创建的临时标头。

【问题讨论】:

你找到相同的解决方案了吗?请分享 查看***.com/a/67559979/6314955 有什么解决办法吗?来自@MalithKuruwita 的上述链接也没有被接受的答案 @EightRice 如果您想将数据发送到接受内容类型的服务器:x-www-form-urlencoded,我提供的上述 URL 有效。它适用于文本数据。但是如果你想发送多部分/表单数据。像文件或图像到服务器(二进制数据),使用它(developerlibs.com/2020/07/…)。该博客还展示了如何发送文本数据。根据服务器接受的内容类型使用相关的 【参考方案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 传递数据。 这在标题字符串之间缺少逗号。

以上是关于如何在颤振中使用表单数据制作 http 帖子?的主要内容,如果未能解决你的问题,请参考以下文章

颤振 |如何将数据添加到 Firestore 中的现有文档

如何使用用户的表单添加内容类型的内容(帖子)

Apache HttpClient 制作多部分表单帖子

在颤振中如果文本内容增加,我想在帖子底部显示更多文本?

如何使用 GridView 或 TableView 在颤振中制作填字游戏

如何正确预填充颤振表单字段?