Flutter http streamedResponse.stream和streamedResponse.sink

问题描述

我正在学习Flutter http软件包的第三个示例,这是代码的基础:https://pub.dev/packages/http

通过BaseClient.send发送请求时,将仅立即发送标头和已写入 StreamedRequest.stream 的所有数据。一旦将数据写入 StreamedRequest.sink ,就会发送更多数据,当接收器关闭时,请求将结束。

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

  1. 从文档中,我不明白我们应该如何写StreamedRequest.stream? (立即发送数据)

  2. StreamedResponse.sink基本上不是我们在其中添加HTTP POST的请求正文的地方:为什么它仅接受List<int>?不应该是Map<String,String>吗?如果不是,那么我们应该在哪里添加请求主体? NEW:即使我使用ut8.encode对其进行编码,但在调试时它仍未显示fiddler的WebForms上,如何正确发送x-www-form-urlencoded?:

代码

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. 为什么必须关闭接收器才能访问StreamedResponse的属性

streamedRequest.sink.close();

更新

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',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();
  }
}

因此,我运行前两个功能,但是在运行_body函数之前,_httpClose()变量不会显示在屏幕上。

解决方法

  1. Map<String,String>无法流式传输。 流式传输是指流每次发送大块数据并且服务器(或浏览器发送缓冲区)准备接收更多数据时,将按大块数据发送数据。 List<int>可以分块,因为一次发送多少字节都没有关系。 如果所有数据都随时可用,则可能不希望使用StreamedRequest,特别是如果它不是数据块时。 https://en.wikipedia.org/wiki/Binary_large_object

utf8.encode可用于对流发出的块进行编码,但它本身不提供流,因此无法将utf8.encode的结果添加到接收器。

  1. 我不明白这个问题。您想访问哪些属性?尝试时遇到什么问题?

在我看来,您不需要在用例中使用StreamedRequest。