Dart HTTP server and Futures

2019-07-19 14:31发布

I am trying to write simple HTTP server which parse result of client.getUrl(). I've got everything working except I am not able to write back to http request object (print to console works fine).

Relevant code is:

main() {
  HttpServer.bind(InternetAddress.ANY_IP_V4, 4040)
      .then((HttpServer server) {
    print('listening on localhost, port ${server.port}');
    server.listen((HttpRequest request) {
      Future loadedContent = loadUrl(furl);
      loadedContent.then((content) => print(content));
  //  loadedContent.then((content) => request.response.write(content));

      request.response.close();
      print ("response closed");
    });
  }).catchError((e) => print(e.toString()));
}

Problem is that main function ends before I get result from Future (figured that out by printing "response closed" which appears second before results). Is there way to wait for results in main function?

Edit: It is related to Dart HttpRequest return future I will rewrite my code, but if there is a way to wait for getUrl Future in main function, I would prefer it.

Edit: my loadUrl

Future loadUrl(String url)
{
  final c = new Completer();
  HttpClient client = new HttpClient();
  client.addCredentials(
          Uri.parse("https://*****.tpondemand.com/api"),
          "tprealm",
          new HttpClientBasicCredentials("*****", "*****"));
  client.getUrl(Uri.parse(url))
      .then((HttpClientRequest request) {
        // Optionally set up headers...
        // Optionally write to the request object...
        // Then call close.

        return request.close();
      })
      .then((HttpClientResponse response) {
        // Process the response.
        //print(response.reasonPhrase);
        response.transform(UTF8.decoder).listen((contents) {
             // handle data
            Map parsedMap = JSON.decode(contents);
            c.complete(parsedMap);
            //req.response.write(parsedMap["Items"][0]);
           });

      });
  return c.future;
  }

last edit: this is working code

import 'dart:io';
import 'dart:async';
import 'package:http_server/http_server.dart';
import 'dart:convert';

final furl = "https://***.tpondemand.com";

Future loadUrlBody(String url) {
  final c = new Completer(); 
  HttpClient client = new HttpClient();
  client.addCredentials(Uri.parse("https://***.tpondemand.com/api"), "tprealm", new HttpClientBasicCredentials("user", "password"));
  client.getUrl(Uri.parse(url))
      .then((HttpClientRequest response) => response.close())
      .then(HttpBodyHandler.processResponse)
      .then((HttpClientResponseBody body) {
       c.complete(body);
      });
  return c.future;
}
main() {
  final filter = "/api/v1/Userstories?format=json&where=(Team.Id+eq+111111)&include=[Name,CreateDate,ModifyDate,LastCommentDate]&take=1000";
  HttpServer.bind(InternetAddress.ANY_IP_V4, 4040).then((HttpServer server) {
    print('listening on localhost, port ${server.port}');
    server.listen((HttpRequest request) {
      print(request.connectionInfo.remoteAddress);
      loadUrlBody(furl + filter).then((content) {
        Map parsedMap = content.body;
        //print("Map parsed");
        request.response.write(parsedMap["Items"]);
        request.response.close();
        //print("response closed");
      }).catchError((e) => print(e.toString()));
    });
  }).catchError((e) => print(e.toString()));
}

1条回答
劫难
2楼-- · 2019-07-19 15:11

When your loadUrl() returns a Future (which it probably should) then this should work

main() {
  HttpServer.bind(InternetAddress.ANY_IP_V4, 4040)
      .then((HttpServer server) {
    print('listening on localhost, port ${server.port}');
    server.listen((HttpRequest request) {
      loadUrl(furl).then(() {
        // loadedContent.then((content) => print(content));
        loadedContent.then((content) => request.response.write(content));

        request.response.close();
        print ("response closed");
      });
    });
  }).catchError((e) => print(e.toString()));
} 

update

You need to modify your getData() or loadUrl() method

Future getData(HttpRequest request) { // added return type 'Future' (not necessary)
  return dao.findAll().then((value) { // added 'return'
    print(value);
  });
}

update 2

Future loadUrl(String url)
{
  // final c = new Completer(); // <== commented out
  HttpClient client = new HttpClient();
  client.addCredentials(
          Uri.parse("https://*****.tpondemand.com/api"),
          "tprealm",
          new HttpClientBasicCredentials("*****", "*****"));
  return client.getUrl(Uri.parse(url))                      // <== added return
      .then((HttpClientRequest request) {
        // Optionally set up headers...
        // Optionally write to the request object...
        // Then call close.

        return request.close();
      })
      .then((HttpClientResponse response) {
        // Process the response.
        //print(response.reasonPhrase);
        return response.transform(UTF8.decoder).listen((contents) { // <== added return
             // handle data
            Map parsedMap = JSON.decode(contents);
            // c.complete(parsedMap); // <== commented out
            //req.response.write(parsedMap["Items"][0]);
           }).asFuture();  // <== added `.asFuture()`

      });
   // return c.future; // <== commented out
}

Normally it should be sufficient to prepend a return before each call to a method that returns a Future, then you can avoid using a completer. Completer are only for more complex situations (for example when you return the completer.future from one method but complete it from somewhere else, for example an event handler).

查看更多
登录 后发表回答