http icon indicating copy to clipboard operation
http copied to clipboard

add Timeout functionality for http package

Open DartBot opened this issue 9 years ago • 25 comments

Originally opened as dart-lang/sdk#19831

This issue was originally filed by [email protected]


What steps will clearly show the issue / need for enhancement?

  1. when making http requests you usually want to timeout the request after a reasonable amount of time (usually in the region of seconds)
  2. it would be great to have away to specify timeout as Duration when making a http request via the http/browser client/http client classes.

What version of the product are you using? On what operating system? Dart 1.5.1, http 0.11.1+1

DartBot avatar Jun 05 '15 22:06 DartBot

<img src="https://avatars.githubusercontent.com/u/188?v=3" align="left" width="48" height="48"hspace="10"> Comment by nex3


Probably the best way to support this would be to add a separate http_timeout_client package that exposes an HttpTimeoutClient that wraps an existing client.

DartBot avatar Jun 05 '15 22:06 DartBot

This comment was originally written by [email protected]


Is there any reason why timeout couldn't be added as an optional parameter to the existing clients? I think the usage pattern would be more obvious this way than having to first create a client, then create another (HttpTimeoutClient) to wrap around it before you do a HTTP request.

DartBot avatar Jun 05 '15 22:06 DartBot

<img src="https://avatars.githubusercontent.com/u/188?v=3" align="left" width="48" height="48"hspace="10"> Comment by nex3


The http package is based on a composition model where each layer (that is, a class implementing http.Client) is very simple and has a well-defined purpose. This model makes it very easy to mix and match functionality, but one of the costs is that the API for a layer has to be very simple in order to keep them easy to implement. It would be bad if everyone implementing their own [http.Client] had to re-implement the timeout logic from scratch.

having to first create a client, then create another (HttpTimeoutClient) to wrap around it before you do a HTTP request.

The API wouldn't be that difficult. The constructor would look something like this:

    HttpTimeoutClient([HttpClient inner])         : _inner = inner == null ? new HttpClient() : inner;

The user only needs to construct one client if they only care about one aspect of the client.

DartBot avatar Jun 05 '15 22:06 DartBot

This comment was originally written by [email protected]


Hi, thanks for the explanation, that makes a lot of sense.

DartBot avatar Jun 05 '15 22:06 DartBot

<img src="https://avatars.githubusercontent.com/u/444270?v=3" align="left" width="48" height="48"hspace="10"> Comment by seaneagan


Doesn't Future.timeout solve this pretty well already?

https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart-async.Future#id_timeout

Example:

    http.read('http://google.com')         .timeout(const Duration(seconds: 5))         .then(...);

DartBot avatar Jun 05 '15 22:06 DartBot

<img src="https://avatars.githubusercontent.com/u/17034?v=3" align="left" width="48" height="48"hspace="10"> Comment by kevmoo


I don't think HttpTimeoutClient can accomplish what we want.

Users would like to actually cancel the inflight request.

dart:html has abort() on HttpRequest dart:io HttpClient* has no equivalente – the idleTimeout just manages keep-alive connections while idea AKAICT


Added Area-Pkg label.

DartBot avatar Jun 05 '15 22:06 DartBot

<img src="https://avatars.githubusercontent.com/u/17034?v=3" align="left" width="48" height="48"hspace="10"> Comment by kevmoo


Marked this as being blocked by dart-lang/sdk#22265.

DartBot avatar Jun 05 '15 22:06 DartBot

Any plan to support it?

tomyeh avatar Aug 18 '17 11:08 tomyeh

This can easily be done through a middleware with the 0.12 implementation.

donny-dont avatar Sep 21 '17 21:09 donny-dont

@nex3 there's also HttpRequest.timeout which we could have a special context for. We might also want to handle the onTimeout if that's the case.

donny-dont avatar Sep 21 '17 22:09 donny-dont

@donny-dont Could you clarify how one could do this as a middleware?

xqwzts avatar Oct 11 '17 16:10 xqwzts

@donny-dont Is any way to set timeout for HttpClient on server side?

jimmyshiau avatar Nov 15 '17 07:11 jimmyshiau

This is sorely needed on the server side. Currently I have a request that establishes connection, but the remote server hangs for 10 minutes before it gives up and closes the connection. The issue is that the connection is established and (in theory) at least some header information is started. As a result the Client.get is blocking. So adding a timeout to the future doesn't work.

So I have something like:

try {
    var resp = await Client.get(uri, headers: h).timeout(new Duration(seconds: 10));
} catch (e) {
    log.warning('Request failed', e);
}

After 10 minutes I get the timeout exception, plus a warning that "the remote server closed connection before all headers were receive". Because the connection itself is established, the timeout on the future isn't trigged until the next event loop, but because the loop is blocked for 10 minutes it's essentially useless.

butlermatt avatar Dec 07 '17 19:12 butlermatt

@butlermatt Under no circumstances should this ever be blocking. It shouldn't be able to block unless something very strange is going on in dart:io. I'd suggest seeing if you can reproduce that with pure dart:io code and then filing an issue against the SDK.

nex3 avatar Dec 07 '17 22:12 nex3

try { var resp = await Client.get(uri, headers: h).timeout(new Duration(seconds: 10)); } catch (e) { log.warning('Request failed', e); } . How can i remove timeout from this code.becuase timeout is depend on network call and without timeout it gives error.

Nitin-Harman avatar Jan 24 '18 12:01 Nitin-Harman

Please add ability to split timeout connect from timeout read.

carmas123 avatar Dec 10 '18 18:12 carmas123

@carmas123 - I don't believe it's possible to set a connect timeout in the dart:html code path so a setting would not be appropriate for this package as it works across both.

Assuming you're using this with dart:io (flutter or VM) you should be able to do it manually.

Construct an IOCLient and pass in an explicitly constructed HttpClient. On that inner client you can set the connectionTimeout

natebosch avatar Dec 10 '18 19:12 natebosch

Very good thank you

carmas123 avatar Dec 11 '18 07:12 carmas123

Hello what is finally the solution to using the timeout with http (get/post methods) package. Can I please get an example?

thenotoriousdev avatar Apr 19 '19 18:04 thenotoriousdev

Any news on this? @thenotoriousdev

alexgarciaju avatar Nov 12 '19 11:11 alexgarciaju

I try to increase the time out as per my server response, but it's timing out after 1min. How to increase timeout? Below is my code, Could you please look into it

  HttpClient httpClient = new HttpClient();
  httpClient.connectionTimeout = Duration(seconds: 600);
  HttpClient.enableTimelineLogging = true;
  HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
  request.headers.set('content-type', 'application/json');
  request.add(utf8.encode(json.encode(params)));
  HttpClientResponse response = await request.close().timeout(const Duration(seconds: 600));
  httpClient.close();
  if (response.statusCode == 200) //Handle response

venkatesh-u avatar Dec 27 '19 11:12 venkatesh-u

any news update?

I just wonder how to set 'writeTimeout'. Can you help me?

  Future<File> _downloadFile(
    HttpClient client,
    String url,
    File saveFile, {
    Duration readTimeout = const Duration(seconds: 10),
  }) async {
    final HttpClientRequest req = await client.getUrl(Uri.parse(url));
    // await req.addStream(Stream<List<int>>.empty());//.timeout(timeLimit/*writeTimeout*/); ???
    final HttpClientResponse resp = await req.close();//.timeout(timeLimit/*requestTimeout*/);
    print('${resp.statusCode} - ${resp.reasonPhrase}');
    if (resp.statusCode == HttpStatus.ok) {
      final Stopwatch watch = Stopwatch()..start();
      IOSink? sink;
      try {
        saveFile.createSync(recursive: true);
        sink = saveFile.openWrite();
        await sink.addStream(resp.timeout(readTimeout/*readTimeout*/));//.timeout(timeLimit/*receiveTimeout*/);
        await sink.close();
      } catch (e) {
        print(e);
        await sink?.close();
        if (saveFile.existsSync()) {
          await saveFile.delete();
        }
      } finally {
        watch.stop();
        print('elapsed: ${watch.elapsed}');
      }
    } else {
      throw HttpException('${resp.statusCode} - ${resp.reasonPhrase}', uri: req.uri);
    }
    return saveFile;
  }

  HttpClient _serverClient({
    Duration connectTimeout = const Duration(seconds: 10),
  }) {
    final HttpClient client = HttpClient();
    client.connectionTimeout = connectTimeout; // connectTimeout
    return client;
  }

droplet-js avatar Nov 10 '21 05:11 droplet-js

If anyone wants a simple connection timeout and uses this package only with dart VM (so, dart io client internally) then I think the best solution would be like this:

import 'dart:io';

import 'package:http/io_client.dart' as http;
import 'package:http/retry.dart';

RetryClient( // the usual client or say for example RetryClient
        http.IOClient(HttpClient()..connectionTimeout = Duration(seconds: 5)),
);

It's also possible to set a session timeout with the same approach.

fatadel avatar Dec 06 '21 01:12 fatadel