连接到服务器时颤振'HttpException: Failed to parse http'



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

以下是我到目前为止所拥有的:

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": "...",
...
}

如何解决此问题?

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

http_parser.dart是Flutter的http API的一部分,因此问题不在于Dio或其他第三方软件包,也不在于您的应用程序代码,而在于您的服务器。

您可以通过使用Android Studio执行"在路径中查找"搜索(在Windows上为Ctrl+Shift+F(,并在下拉列表中选择"范围"one_answers"所有位置"的同时搜索"无法解析HTTP"来查找文件/函数。您还可以在抛出这些异常的行上放置断点,这将有助于将问题缩小到特定的失败。

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

编辑:_doParse函数上面有以下注释:

// 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,这将解释异常。

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

颤振:

可能您的问题是由于证书在某些平台中无效而引起的,您可以使用以下方法:

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 URL(请参阅有关ClearTextTraffic的信息(。

如果您的应用程序目标为API 28级,则您必须在应用程序内部仅使用https://URL,或者您可以启用允许从应用程序中使用http://,并在AndroidManifest.xml:内部添加

android:usesCleartextTraffic=真正的

示例:

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

最新更新