Http POST 在 Postman 中有效,但在 Flutter 中无效

Posted

技术标签:

【中文标题】Http POST 在 Postman 中有效,但在 Flutter 中无效【英文标题】:Http POST works in Postman but not in Flutter 【发布时间】:2020-04-28 22:58:42 【问题描述】:

我正在尝试使用 Http 包对我的颤振应用程序执行 POST 请求。我首先在 Api 沙盒网站上测试了我的请求,然后在 Postman 中测试了我的请求。它在那里运行良好,但是一旦在 Flutter 中,我总是收到 400 Bad Request。

这是我在 Flutter 中的代码:

import 'package:http/http.dart';
import 'package:uuid/uuid.dart';
import 'package:wave_app/env/secrets.dart';
import 'package:wave_app/models/momo_token.dart';

    String url = "https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay";
    var uuid = Uuid();
    String requestId = uuid.v4();
    MomoToken token = await _createMomoNewTokenCollection();

    String auth = "Bearer " + token.accessToken;

    Map<String, String> headers = 
      "Authorization": auth,
      "X-Target-Environment": "sandbox",
      "X-Reference-Id": requestId,
      "Content-Type": "application/json",
      "Ocp-Apim-Subscription-Key": momoCollectionSubscriptionKey
    ;

    String jsonBody = '"amount": "5","currency": "EUR", "externalId": "123", "payer": "partyIdType": "MSISDN","partyId": "46733123454", "payerMessage": "tripId-123456","payeeNote": "driverId-654321"';

    Response response = await post(url, headers: headers, body: jsonBody);
    int statusCode = response.statusCode;

    print("STATUS CODE REQUEST TO PAY " + statusCode.toString());
    print(response.reasonPhrase.toString());
    print(response.body.toString());

    if (statusCode == 202) 
      return response.body.toString();
     else 
      return null;
    
  

api 文档在这里:https://momodeveloper.mtn.com/docs/services/collection/operations/requesttopay-POST?

这是我的 Postman 请求 curl 中的代码(使用与 requestId、auth、momoCollectionSubscriptionKey 相同的变量)

curl --request POST \
  --url https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay \
  --header 'Accept: */*' \
  --header 'Accept-Encoding: gzip, deflate' \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6IjFmY2MzMjBhLTM0NWQtMTFlYS04NTBkLTJlNzI4Y2U4ODEyNSIsImV4cGlyZXMiOiIyMDIwLTAxLTExVDE1OjU3OjE4Ljc3NyIsInNlc3Npb25JZCI6ImZmYzc1OGE2LTM2MWEtNDM4ZS1hYjE5LWQ1ZGQ4ZmU4ZjEyOSJ9.DeoJyU6Hb0he_or1XeBxW-6s-xwdtmi0cUrYjQe0Z796bIGvvT-VJ214JaZItG-CBQpgv7dHbLfXNqr8D05Q7U9XiOtpr8mtYWQlY-MseGIHAyxp1qBuQkwjmBYBlDxQOYYfzG9SZ8tGFUI1_k59LMNYIhDlXXKa68Ym1sylZ8wfWjGuHaKVzMEH25ubiBwCLev5IHPchuF3toVP99U-HC8t95E3zrEt9dHgzn0hnwvpB31wcsu_b3vb-YZ1idHgosPc2GmKFsDruX14VniKBicCsnGHqZAkSPXwaOR6SIn4JZEEwhAIj3Oe2H5dwxloiX5rzaApdkwEg6KSoBXk8A' \
  --header 'Cache-Control: no-cache' \
  --header 'Connection: keep-alive' \
  --header 'Content-Length: 194' \
  --header 'Content-Type: application/json' \
  --header 'Host: sandbox.momodeveloper.mtn.com' \
  --header 'Ocp-Apim-Subscription-Key: 281eb****************' \
  --header 'Postman-Token: ece19062-1f0b-4873-a3ed-1bd4ada8746a,528004b2-410d-4653-9909-5197a3dc95db' \
  --header 'User-Agent: PostmanRuntime/7.20.1' \
  --header 'X-Reference-Id: 062f8aad-f529-4d0a-804c-affb888c2b8b' \
  --header 'X-Target-Environment: sandbox' \
  --header 'cache-control: no-cache' \
  --data '\r\n  "amount": "5",\r\n  "currency": "EUR",\r\n  "externalId": "123",\r\n  "payer": \r\n    "partyIdType": "MSISDN",\r\n    "partyId": "46733123454"\r\n  ,\r\n  "payerMessage": "hi",\r\n  "payeeNote": "hi"\r\n'

在邮递员及其网站上,我总是收到 202 Accepted 响应。 我不确定,我在这里做错了什么。任何帮助将不胜感激!

------------ 编辑 -------

我也尝试过使用 HttpClient,这是代码,但仍然收到 400 Bad Request

HttpClient httpClient = new HttpClient();
    HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));

    request.headers.set("Authorization", "Bearer " + token.accessToken);
    request.headers.set('content-type', 'application/json');
    request.headers.set("X-Target-Environment", "sandbox");
    request.headers.set("X-Reference-Id", requestId);
    request.headers.set("Ocp-Apim-Subscription-Key", momoCollectionSubscriptionKey);

    request.add(utf8.encode(jsonBody));
    HttpClientResponse response = await request.close();

    print("STATUS CODE " + response.statusCode.toString() + "   " + response.reasonPhrase);
    String reply = await response.transform(utf8.decoder).join();
    print("REPLY " + reply);
    httpClient.close();

【问题讨论】:

您的 Dart 代码似乎是正确的。但是,如果不将自己注册到您尝试使用的网站,我们就无法真正对此进行测试。 这可能是偶尔出现的服务器问题。 post 将通过两种方式修改内容类型。 (1) 它将标头名称小写为content-type,(2) 它将值更改为application/json; charset=utf-8。调整你的 curl 命令来模仿这些,看看它是成功还是失败。如果问题是 (2) 解决方案很简单:将 body: jsonBody 更改为 body: utf8.encode(jsonBody)。 (1) 的解决方案比较棘手。 @RichardHeap 我刚试过这个: --header 'content-type: application/json; charset=utf-8' 在我的卷曲中,我在邮递员中接受了 202。在我的颤振应用程序中仍然有 400 个错误请求。您对问题的根源还有其他想法吗?感谢您的帮助! 尝试其他建议,只是为了好玩。然后断言 curl 适用于 all 小写标题名称,例如ocp-apim-subscription-key @RichardHeap,我尝试使用小写标题,但在 Postman 上失败了。 opc-apim-subscription-key 小写有效,但 x-target-environment 和 x-reference-id 因 400 bad request 而失败。你知道我如何在颤动中绕过强制小写吗? 【参考方案1】:

这绝对是服务器的问题。服务器正在处理两个标头 X-Reference-IdX-Target-Environment 区分大小写(即它不符合 RFC)。

这是 Dart 的 io.HttpClient 强制标题为小写,因此这会影响 package:httppackage:dio 两者都依赖它。有一个request 允许客户端保留标头的大小写,但由于这是一项重大更改,因此进展缓慢。

同时,尝试使用保留标头大小写的客户端分支。 https://pub.dev/packages/alt_http/

【讨论】:

好的,非常感谢您的回答和您的时间。我会试试那个包。很抱歉聊天问题,不知道为什么它仍然无法正常工作。 至少你现在应该可以投票了——哈哈 :-)【参考方案2】:

通过将 jsonBody 从 String 更改为 Map 解决了同样的问题。

 String jsonBody = '"amount": "5","currency": "EUR", "externalId": "123", "payer": "partyIdType": "MSISDN","partyId": "46733123454", "payerMessage": "tripId-123456","payeeNote": "driverId-654321"';

只有当从String -> Map改变时才解决;

 Map jsonBody = "amount": "5","currency": "EUR", "externalId": "123", "payer": "partyIdType": "MSISDN","partyId": "46733123454", "payerMessage": "tripId-123456","payeeNote": "driverId-654321";

此外,还包括 jsonEncode

Response response = await post(url, headers: headers, body: jsonEncode(jsonBody));

jsonEncode 需要导入转换库

import 'dart:convert';

【讨论】:

以上是关于Http POST 在 Postman 中有效,但在 Flutter 中无效的主要内容,如果未能解决你的问题,请参考以下文章

postman post请求 header 和body怎么用

Multipart POST 适用于 Postman,但不适用于 Angular Http Client

简单的 POST 请求在 Postman 中有效,但在浏览器中无效

POST 请求在 Postman 中有效,但在 Python 请求中无效(200 响应机器人检测)

HTTP 请求在 Postman 中有效,但在 C# 代码中无效

CORS 正在阻止 PUT、DELETE 和 POST 请求,但 GET 正在工作