设置HTTPClient get()请求的超时

时间:2018-07-23 22:08:32

标签: dart flutter

此方法提交一个简单的HTTP请求并调用成功或错误回调:

  void _getSimpleReply( String command, callback, errorCallback ) async {

    try {

      HttpClientRequest request = await _myClient.get( _serverIPAddress, _serverPort, '/' );

      HttpClientResponse response = await request.close();

      response.transform( utf8.decoder ).listen( (onData) { callback( onData ); } );

    } on SocketException catch( e ) {

      errorCallback( e.toString() );

    }
  }

如果服务器未运行,则Android应用或多或少会立即调用errorCallback。

在iOS上,errorCallback会花费很长的时间-超过20秒-直到调用任何回调。

我可以为HttpClient()设置等待服务器端返回回复的最大秒数-如果有的话?

4 个答案:

答案 0 :(得分:24)

您可以使用timeout

http.get('url').timeout(
  Duration(seconds: 1),
  onTimeout: () {
    // time has run out, do what you wanted to do
    return null;
  },
);

答案 1 :(得分:8)

有两种方法可以在Dart中配置此行为

设置每个请求超时

您可以使用Future.timeout方法在任何Future上设置超时。在给定的持续时间过去之后,这会通过抛出TimeoutException来短路。

try {
  final request = await client.get(...);
  final response = await request.close()
    .timeout(const Duration(seconds: 2));
  // rest of the code
  ...
} on TimeoutException catch (_) {
  // A timeout occurred.
} on SocketException catch (_) {
  // Other exception
}

在HttpClient上设置超时

您还可以使用HttpClient.connectionTimeout在HttpClient本身上设置超时。设置超时后,这将适用于同一客户端发出的所有请求。当请求超过此超时时间时,将引发SocketException

final client = new HttpClient();
client.connectionTimeout = const Duration(seconds: 5);

答案 2 :(得分:3)

HttpClient.connectionTimeout 对我不起作用。但是,我知道 Dio 数据包允许取消请求。然后,我深入研究数据包以了解他们是如何实现它的,并根据我的需要进行了调整。我所做的是创建两个未来:

  • 一个 Future.delayed,我可以在其中设置超时的持续时间。
  • HTTP 请求。

然后,我将两个期货传递给 Future.any,它返回要完成的第一个期货的结果,并丢弃所有其他期货的结果。因此,如果超时未来先完成,您的连接将超时并且不会收到任何响应。您可以在以下代码中查看:

Future<Response> get(
    String url, {
    Duration timeout = Duration(seconds: 30),
  }) async {
    
    final request = Request('GET', Uri.parse(url))..followRedirects = false;
    headers.forEach((key, value) {
      request.headers[key] = value;
    });

    final Completer _completer = Completer();

    /// Fake timeout by forcing the request future to complete if the duration
    /// ends before the response arrives.
    Future.delayed(timeout, () => _completer.complete());

    final response = await Response.fromStream(await listenCancelForAsyncTask(
      _completer,
      Future(() {
        return _getClient().send(request);
      }),
    ));
  }
    
  Future<T> listenCancelForAsyncTask<T>(
    Completer completer,
    Future<T> future,
  ) {
    /// Returns the first future of the futures list to complete. Therefore,
    /// if the first future is the timeout, the http response will not arrive
    /// and it is possible to handle the timeout.
    return Future.any([
      if (completer != null) completeFuture(completer),
      future,
    ]);
  }

  Future<T> completeFuture<T>(Completer completer) async {
    await completer.future;
    throw TimeoutException('TimeoutError');
  }

答案 3 :(得分:1)

没有使用Dart的http设置超时的选项。但是,当它返回Future时,我们可以在Future上设置超时。

下面的示例将超时设置为15秒。如果已经15秒并且没有收到响应,它将抛出TimeoutException

Future<dynamic> postAPICall(String url, Map param, BuildContext context) async {
  try {
    final response =  await http.post(url,
        body: param).timeout(const Duration(seconds: 10),onTimeout : () {
      throw TimeoutException('The connection has timed out, Please try again!');
    });

    print("Success");
    return response;
  } on SocketException {
    print("You are not connected to internet");
  }
}