【问题标题】:Flutter 'HttpException: Failed to parse http' when connecting to serverFlutter 'HttpException: Failed to parse http' 连接到服务器时
【发布时间】:2020-03-10 18:55:38
【问题描述】:

我有一个 Flutter 应用程序正在尝试使用 Dio 包连接到服务器 API。服务器使用自签名证书,这意味着使用 Dio 解决方法来验证证书以连接到服务器(请参阅https://pub.dev/packages/dio#https-certificate-verification)。

以下是我目前所拥有的:

String url = 'https://...';             // Server API URL
Map<String, dynamic> data = ... // Request body
String PEM = "XXXXX";           // Certificate content

Dio dio = Dio();

(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate  = (client) {
    client.badCertificateCallback=(X509Certificate cert, String host, int port){
        if (cert.pem == PEM) {
            // Verify the certificate
            return true;
        }
        return false;
    };
};

Response response = await dio.post(url, data: data);

但是这会引发 HttpException:

HttpException: Failed to parse HTTP, uri = https://... // Server API url

异常中没有显示其他信息。 response.data 的值为null

请务必注意,服务器实际上正在响应数据 - 所以这似乎是 Flutter / 客户端问题。服务器响应是字符串字段和值的标准对象:

{
    "status": "ok",
    "token": "...",
    "field1": "...",
    "field2": "...",
    "field3": "...",
    ...
}

我该如何解决这个问题?

【问题讨论】:

  • 你能提供实际的URI吗?
  • 您能否分享更多信息,以便我们从头开始重现该问题?
  • 您能在涉及任何 d’art 代码之前向我们展示网络响应吗?

标签: android ios flutter dart


【解决方案1】:

该异常仅由http_parser.dart 文件中的两个函数引发:_expect_expectHexDigit。这两个函数又在几个不同的地方被调用,它们都在同一个文件的_doParse 函数中。对从客户端-服务器连接流接收到的字节调用此函数。

http_parser.dart 是 Fl​​utter 的 http API 的一部分,因此问题不在于 Dio 或其他 3rd 方包,或者您的应用程序代码,而在于您的服务器。

您可以通过使用 Android Studio 执行“在路径中查找”搜索(在 Windows 上为 Ctrl + Shift + F)并搜索“无法解析 HTTP”,同时选择“范围”以及“下拉列表中的所有地点。您还可以在引发这些异常的行上放置断点,这应该有助于您将问题缩小到特定的故障。

您会注意到大多数_expect 函数调用都在检查响应的各个部分之间的“LF”或“CR”字符(换行符),但确定问题所在的唯一方法是通过断点调试和深入挖掘。

编辑:_doParse 函数上面有以下 cmets:

// From RFC 2616.
// generic-message = start-line
//                   *(message-header CRLF)
//                   CRLF
//                   [ message-body ]
// start-line      = Request-Line | Status-Line
// Request-Line    = Method SP Request-URI SP HTTP-Version CRLF
// Status-Line     = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
// message-header  = field-name ":" [ field-value ]

它只是希望您的服务器响应在响应分段和分段之间的换行符方面符合 RFC 2616。也许有一些工具可以用来检查您的服务器/端点是否符合 RFC 2616? RFC 2616 是 HTTP/1.1 协议,因此,例如,如果您的服务器使用 HTTP/2.0,则可以解释该异常。

【讨论】:

  • 嗨,这对了解真的很有帮助,谢谢。如何在 Android Studio 中包含 Flutter 引擎文件?由于项目文件夹在 Android Studio 中打开(并且 Flutter 文件在其他地方),因此选择“Scope”进行搜索仍然只包括项目文件夹中的文件。
  • 澄清一下,我的意思是将 Flutter 引擎文件添加到 Android Studio 以便向它们添加断点(具体来说,http_parser.dart)。
  • 正如我上面提到的,除了选择“范围”之外,您还需要从选择“范围”后显示的下拉列表中选择“所有地点”。您无需执行任何其他操作即可搜索这些文件。
  • 还有一种“手动”方式导航到该文件 - 进入“外部库”(Android Studio 中项目资源管理器的底部),然后进入“Dart Packages/sky_engine/_http/http_parser” .dart'
  • 感谢您到目前为止的帮助。我发现 Android Studio 似乎不知道添加到 http_parser.dart 的断点。是否有在 AS 中启用此功能的选项?
【解决方案2】:

您是否在 Android 上进行测试?如果是这样,默认情况下它只会连接到 HTTPS 端点,但您可以通过将 android:usesCleartextTraffic="true" 添加到 AndroidManifest.xml 进行测试来解决此问题。

【讨论】:

  • 端点是 HTTPS,我已更新问题以澄清这一点。
【解决方案3】:

颤振:

你的问题可能是因为证书在某些平台上无效,你可以使用这个方法:

if (Platform.isAndroid) {
    (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
        client.badCertificateCallback = (X509Certificate cert, String host, int port) {
            if (cert.pem == PEM) {
                // Verify the certificate
                return true;
            }
            return false;
        };
    };
}

安卓:

由于默认情况下不允许使用非 SSL 的 Android 9.0 网址(请参阅ClearTextTraffic)。

如果您的应用面向 API 级别 28,则您必须仅在应用内使用 https:// 网址,或者您可以启用以允许在您的应用中使用 http://,并在您的 AndroidManifest.xml 内添加:

android:usesCleartextTraffic=true

示例:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-18
    • 2019-01-01
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 2017-02-12
    • 2017-10-26
    相关资源
    最近更新 更多