Многоразовый запрос синхронизации HttpClient

Мне нужна многократно используемая функция, которая делает HTTP-запрос и ожидает его завершения, прежде чем вернуть ответ в виде строки.

Вот основная функция:

main() async {
  var json;
  json = await makeRequest('https://...');
  print(json);
  print('*** request complete ***');
}

(Первый случай) Это повторно используемая функция, которая делает HTTP-запрос:

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;
  }
}

Это работает, как ожидалось, и вывод:

// Response contents as a String...
*** request complete ***

(Второй случай) Затем я попытался сделать это, и это не сработало:

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;
}

Я пытался определить функцию внутри listen с async а также await, возвращаясь contents в listen без onDone(), но вывод такой же:

// Empty line.
*** request complete ***
// Waits a few seconds doing nothing before terminating...

Кто-нибудь знает, почему второй случай не работает?

РЕДАКТИРОВАТЬ:

После обновления кода он делает то, что должен был сделать, но занимает несколько секунд перед прекращением выполнения:

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;
}

Выход:

// Prints response contents...
*** request complete ***
// Takes a few seconds before execution terminates. With the break the code terminates immediately.

EDIT2:

После отправки этого вопроса на GitHub я узнал, что экземпляры HttpClient иметь пул соединений и поддерживать постоянные соединения по умолчанию, что поддерживает работу виртуальной машины Dart. Пожалуйста, обратитесь к странице вопроса, чтобы узнать о возможных решениях.

1 ответ

Решение

Это, вероятно, вызвано await перед response.transform,

Вы можете захотеть что-то вроде

  return response.transform(UTF8.decoder).join('');

Пауза не связана с makeRequest(), Виртуальная машина Dart, кажется, что-то ждет, прежде чем она выйдет. Добавление exit(0); как последняя строка в main() немедленно завершает работу приложения.

Обновить

Согласно ответу на вопрос Dart SDK

Это вызвано тем, что экземпляр HttpClient имеет пул соединений, который может поддерживать виртуальную машину Dart. Есть два способа избежать этого:

1) Закройте HttpClient явно
2) Используйте непостоянные соединения

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);
}
Другие вопросы по тегам