3

我需要一个可重用的函数来发出 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;
}

我尝试在listenwith asyncand内定义函数,在without内await返回,但输出是相同的:contentslistenonDone()

// 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.

编辑2:

在GitHub 上提交这个 issue 后,我发现实例HttpClient有一个连接池并默认保持持久连接,这使 Dart VM 保持活动状态。请查阅问题页面以了解可能的解决方案。

4

1 回答 1

2

应该是前段时间造成awaitresponse.transform

你可能想要类似的东西

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

暂停与 无关makeRequest()。Dart VM 似乎在退出之前等待某些东西。添加exit(0);为最后一行main()会使应用程序立即退出。

更新

根据对Dart SDK 问题的响应

这是因为 HttpClient 实例有一个连接池,可以让 Dart VM 保持活动状态。有两种方法可以避免这种情况:

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);
}
于 2015-08-09T15:02:22.177 回答