Flutter http streamedResponse.stream and streamedResponse.sink

Issue

I’m learning the third example of Flutter http package, this is the base of the code: https://pub.dev/packages/http

When the request is sent via BaseClient.send, only the headers and whatever data has already been written to StreamedRequest.stream will be sent immediately. More data will be sent as soon as it’s written to StreamedRequest.sink, and when the sink is closed the request will end.

https://pub.dev/documentation/http/latest/http/StreamedRequest-class.html

  1. From the docs, I don’t understand how we should write to StreamedRequest.stream? (To send data immediately)

  2. Isn’t StreamedResponse.sink basically where we add our HTTP POST’s Request Body: Why does it only accept a List<int>? Shouldn’t it be a Map<String, String>? If it’s not then where should we add the request body? NEW: Even when I encode it with ut8.encode, it still doesn’t show up on Fiddler’s WebForms when I’m debugging, how do I send a x-www-form-urlencoded properly?:

Code:

userAgentClient = UserAgentClient(userAgent, client);
streamedRequest = http.StreamedRequest('POST', Uri(scheme: 'http', path: '/posts/', host: 'jsonplaceholder.typicode.com'));
streamedRequest.sink.add([123, 456]); // It has to be a List<int>

//NEW:
streamedRequest.sink.add(utf8.encode('username=123&password=456'));
streamedRequest.sink.add(utf8.encode('{"username":"123","password":"456"}'));
  1. Why do I have to close the sink to be able to access StreamedResponse’s properties?

streamedRequest.sink.close();

Update:

class UserAgentClient extends http.BaseClient {
  final String userAgent;
  final http.Client client;
  UserAgentClient(this.userAgent, this.client);
  Future<http.StreamedResponse> send(http.BaseRequest request){
    request.headers['user-agent'] = userAgent;
    return client.send(request);
  }
}

dynamic _status = '';
dynamic _body = '';
dynamic _headers = '';
String _reason = '';
http.Client client = http.Client();
String userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36';
UserAgentClient userAgentClient;
http.StreamedRequest streamedRequest;

void _httpStreamed(){
  userAgentClient = UserAgentClient(userAgent, client);
  streamedRequest = http.StreamedRequest('POST', Uri(scheme: 'http', path: '/posts/', host: 'jsonplaceholder.typicode.com'));
  streamedRequest.sink.add(utf8.encode('{"username":"123","password":"456"}'));
  setState(() {
    _status = streamedRequest.url;
    _body = '';
    _headers = '';
    _reason = '';
  });
}

void _httpSend() async{
    http.StreamedResponse streamedResponse;
    streamedResponse = await userAgentClient.send(streamedRequest);
    streamedResponse.stream.listen(
      (value) async{
          _body = http.ByteStream.fromBytes(value);
          _body = await _body.bytesToString();
      },
      onError: (e, sT) {
        SnackBar sBar = SnackBar(content: Text('$e\n$sT',));
        Scaffold.of(context).showSnackBar(sBar);
      },
      onDone: () {
        SnackBar sBar = SnackBar(content: Text('Done lol'),);
        Scaffold.of(context).showSnackBar(sBar);
      },
    );
    setState(() {
      _body;
      _status = streamedResponse.statusCode;
      _headers = streamedResponse.headers;
      _reason = streamedResponse.reasonPhrase;
    });
  }
}

void _httpClose(){
  if (streamedRequest != null){
    streamedRequest.sink.close();
  }
}

So I run the first 2 functions but the _body variable doesn’t show up on my screen until I run the _httpClose() function.

Solution

  1. yes

  2. Map<String,String> can not be streamed.
    Streamed means the data is sent in chunks every time a chunk of data is emitted by the stream and the server (or the browsers send buffer) is ready to receive more data.
    List<int> can be chunked because it doesn’t matter how many bytes are sent at once.
    If you have all data readily available, you probably do not want to use a StreamedRequest, expecially if it is not a blob of data. https://en.wikipedia.org/wiki/Binary_large_object

utf8.encode can be used to encode chunks emitted by a stream, but it doesn’t provide a stream by itself, so you can’t add the result of utf8.encode to a sink.

  1. I do not understand that question. What properties doe you want to access and what problems do you run into when you try?

To me it doesn’t look like you don’t need to use StreamedRequest for your use case.

Answered By – Günter Zöchbauer

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.