http
http copied to clipboard
add Timeout functionality for http package
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?
- when making http requests you usually want to timeout the request after a reasonable amount of time (usually in the region of seconds)
- 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
<img src="https://avatars.githubusercontent.com/u/2108507?v=3" align="left" width="48" height="48"hspace="10"> Comment by dgrove
Added Pkg-Http, Triaged labels.
<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.
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.
<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.
This comment was originally written by [email protected]
Hi, thanks for the explanation, that makes a lot of sense.
<img src="https://avatars.githubusercontent.com/u/188?v=3" align="left" width="48" height="48"hspace="10"> Comment by nex3
Issue #10 has been merged into this issue.
<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(...);
<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.
<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.
Any plan to support it?
This can easily be done through a middleware with the 0.12 implementation.
@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 Could you clarify how one could do this as a middleware?
@donny-dont Is any way to set timeout for HttpClient on server side?
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 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.
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.
Please add ability to split timeout connect from timeout read.
@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
Very good thank you
Hello what is finally the solution to using the timeout with http (get/post methods) package. Can I please get an example?
Any news on this? @thenotoriousdev
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
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;
}
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.