Reputation: 358
I need a reusable function that makes an HTTP request and awaits for its completion before returning the response as a String.
Here's the main function:
main() async {
var json;
json = await makeRequest('https://...');
print(json);
print('*** request complete ***');
}
(First Case) This is the reusable function that makes the HTTP request:
makeRequest(String url) async {
var request = await new HttpClient().postUrl(Uri.parse(url));
// Includes the access token in the request headers.
request.headers.add(...);
// Waits until the request is complete.
var response = await request.close();
await for (var contents in response.transform(UTF8.decoder)) {
return contents;
}
}
This works as expected and the output is:
// Response contents as a String...
*** request complete ***
(Second Case) Then I tried to do this and it didn't work:
makeRequest(String url) async {
var request = await new HttpClient().postUrl(Uri.parse(url));
// Includes the access token in the request headers.
request.headers.add(...);
// Waits until the request is complete.
var response = await request.close();
var json = '';
await response.transform(UTF8.decoder).listen((contents) {
// At first I tried to return contents here, but then I added onDone().
json += contents;
}, onDone: () {
return json;
});
return json;
}
I've tried defining the function within listen
with async
and await
, returning contents
within listen
without onDone()
, but the output is the same:
// Empty line.
*** request complete ***
// Waits a few seconds doing nothing before terminating...
Does anyone know why the second case doesn't work?
EDIT:
After updating the code it does what it was supposed to do, but takes a few seconds before terminating execution:
Future<String> twitterRequest(String url) async {
var request = await new HttpClient().postUrl(Uri.parse(url));
// Includes the access token in the request headers.
request.headers.add(...);
// Waits until the request is complete.
var response = await request.close();
var json = '';
await for (var contents in response.transform(UTF8.decoder)) {
json += contents;
// Putting a break here produces the same output but terminates immediately (as wanted).
}
return json;
}
Output:
// Prints response contents...
*** request complete ***
// Takes a few seconds before execution terminates. With the break the code terminates immediately.
EDIT2:
After submitting this issue on GitHub, I found out that instances of the HttpClient
have a connection pool and keep persistent connections by default, which keeps the Dart VM alive. Please consult the issue page to find out about the possible solutions.
Upvotes: 3
Views: 2098
Reputation: 657909
It's probably caused by the await
before the response.transform
.
You might want something like
return response.transform(UTF8.decoder).join('');
The pause is not related to makeRequest()
. The Dart VM seems to wait for something before it exits. Adding exit(0);
as last line in main()
makes the application exit immediately.
Update
According to the response on the Dart SDK issue
This is caused by the HttpClient instance having a connection pool which can keep the Dart VM alive. There are two ways of avoiding this:
1) Close the HttpClient explicitly
2) Use non-persistent connections
import 'dart:async';
import 'dart:convert' show UTF8;
import 'dart:io';
Future main() async {
await makeRequest();
print('end of main');
}
Future makeRequest() async {
var client = new HttpClient();
var request = await client.postUrl(Uri.parse('https://example.com'));
var response = await request.close();
var contents = await response.transform(UTF8.decoder).join();
print(contents);
client.close(); // Close the client.
}
import 'dart:async';
import 'dart:convert' show UTF8;
import 'dart:io';
Future main() async {
await makeRequest();
print('end of main');
}
Future makeRequest() async {
var request = await new HttpClient().postUrl(Uri.parse('https://example.com'));
request.persistentConnection = false; // Use non-persistent connection.
var response = await request.close();
var contents = await response.transform(UTF8.decoder).join();
print(contents);
}
Upvotes: 2